Java内部类的4种用法详解(附带实例)
在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
根据内部类的位置、修饰符和定义的方式,Java 程序里可以将内部类分为四种,分别是成员内部类、局部内部类、静态内部类和匿名内部类。
内部类有三个共性:
同时,若要在外部类外访问内部类,则需要外部类对象去创建内部类对象,在外部类外创建内部类对象的语法格式如下。
【实例】定义一个外部类 Grade 和一个成员内部类,通过测试类测试外部类和内部类的使用原则。
局部内部类在方法外是无法访问到的,但它的实例可以从方法中返回,并且实例在不再被引用之前会一直存在。
局部内部类也可以访问所在方法的局部变量、方法参数等,限制是局部变量或方法参数只有在声明为 final 时才能被访问。
【实例】定义外部类 TestInnerClass1 和内部类 MInner,并测试外部类和内部类相互访问的原则。
静态内部类可以定义实例成员和静态成员,可以直接访问外部类的静态成员,但如果要访问外部类的实例成员,必须通过外部类对象访问。
另外,如果在外部类外访问静态内部类成员,则不需要创建外部类对象,只需要创建内部类对象即可。
【实例】定义类 Outter,并在其内部定义静态类 Inner,在测试类 TestStaticInner 中测试访问静态内部类的原则。
匿名内部类的语法格式如下:
【实例】定义抽象类 Bird,在测试类 TestAnonyClass 中定义匿名类实现 Bird 类,重写 Bird 类中的抽象方法。
在使用匿名内部类的过程中,应注意以下几点:
根据内部类的位置、修饰符和定义的方式,Java 程序里可以将内部类分为四种,分别是成员内部类、局部内部类、静态内部类和匿名内部类。
内部类有三个共性:
- 内部类与外部类经 Java 编译器编译后生成的两个类是独立的;
- 内部类是外部类的一个成员,因此能访问外部类的任何成员(包括私有成员),但外部类不能直接访问内部类成员;
- 内部类可为静态,可用 protected 和 private 修饰。
Java成员内部类
成员内部类可以看成是外部类的一个成员,能直接访问外部类的所有成员,但在外部类中访问内部类,则需要在外部类中创建内部类的对象,使用内部类的对象访问内部类的成员。同时,若要在外部类外访问内部类,则需要外部类对象去创建内部类对象,在外部类外创建内部类对象的语法格式如下。
外部类名.内部类名 引用变量名 = new 外部类名().new 内部类名();下面通过一个例子演示成员内部类的使用原则。
【实例】定义一个外部类 Grade 和一个成员内部类,通过测试类测试外部类和内部类的使用原则。
class Grade { private int count; class Student { private String name; Student(String name) { this.name = name; } public void addGrage() { count++; } } public void add() { Student s = new Student("John"); s.addGrage(); // 在外部类内使用内部类成员,需要通过创建内部类对象来访问 System.out.println("欢迎 " + s.name + " 加入班级!目前班级人数:" + count); } } public class TestInnerClass { public static void main(String[] args) { Grade g = new Grade(); // 在外部类外使用内部类 Grade.Student john = g.new Student("John"); g.add(); } }运行该程序,结果为:
欢迎 John 加入班级!目前班级人数:1
Java局部内部类
局部内部类的使用和成员内部类的使用基本一致,只是局部内部类定义在外部类的方法中,就像局部变量一样,并不是外部类的成员。局部内部类在方法外是无法访问到的,但它的实例可以从方法中返回,并且实例在不再被引用之前会一直存在。
局部内部类也可以访问所在方法的局部变量、方法参数等,限制是局部变量或方法参数只有在声明为 final 时才能被访问。
【实例】定义外部类 TestInnerClass1 和内部类 MInner,并测试外部类和内部类相互访问的原则。
public class TestInnerClass1 { public void show() { // 外部类中的方法 final int a = 20; int b = 15; // 方法内部类 class MInner { int c = 2; // 内部类中的变量 public void print() { System.out.println("访问外部类的方法中的常量 a:" + a); System.out.println("访问内部类中的变量 c:" + c); } } MInner mi = new MInner(); // 创建方法内部类的对象 mi.print(); // 调用内部类的方法 } public static void main(String[] args) { TestInnerClass1 test = new TestInnerClass1(); // 创建外部类的对象 test.show(); // 调用外部类的方法 } }程序的执行结果如下:
访问外部类的方法中的常量 a:20
访问内部类中的变量 c:2
Java静态内部类
如果不需要外部类对象与内部类对象之间有联系,可以将内部类声明为 static,称为静态内部类。静态内部类可以定义实例成员和静态成员,可以直接访问外部类的静态成员,但如果要访问外部类的实例成员,必须通过外部类对象访问。
另外,如果在外部类外访问静态内部类成员,则不需要创建外部类对象,只需要创建内部类对象即可。
【实例】定义类 Outter,并在其内部定义静态类 Inner,在测试类 TestStaticInner 中测试访问静态内部类的原则。
class Outer { // 定义类静态成员 private static String name = "Outter"; private static int id; // 定义静态内部类 public static class Inner { public static String name = "Outter.inner"; public void print() { System.out.print(Outter.name); System.out.println(":" + id); } } } public class TestStaticInner { public static void main(String[] args) { // 访问静态内部类的静态成员 String s = Outter.Inner.name; System.out.println(s); // 创建静态内部类对象 Outter.Inner inner = new Outter.Inner(); inner.print(); } }运行程序,结果为:
Outter.inner
Outter:0
Java匿名内部类
如果某个类的实例只使用一次,则可以将类的定义与类对象的创建,放到一起完成,或者说在定义类的同时就创建一个类对象。匿名内部类的语法格式如下:
new className(){ //匿名内部类的类体 }这种形式的 new 语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。它还创建那个类的一个新实例,并把它作为语句的结果而返回。要扩展的类和要实现的接口是 new 语句的操作数,后跟匿名类的主体。
【实例】定义抽象类 Bird,在测试类 TestAnonyClass 中定义匿名类实现 Bird 类,重写 Bird 类中的抽象方法。
abstract class Bird { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract int fly(); } public class TestAnonyClass { public void test(Bird bird) { System.out.println(bird.getName() + " 能够飞 " + bird.fly() + " 米"); } public static void main(String[] args) { TestAnonyClass test = new TestAnonyClass(); test.test(new Bird() { // 匿名内部类 public int fly() { return 10000; } public String getName() { return "大雁"; } }); } }程序运行结果为:
大雁 能够飞 10000 米
在 TestAnonyClass 类中,test() 方法接收一个 Bird 类型的参数,同时我们知道一个抽象类是没有办法直接 new 的,所以在 main() 方法中直接使用匿名内部类来创建一个 Bird 实例。在使用匿名内部类的过程中,应注意以下几点:
- 使用匿名内部类时,必须是继承一个类或者实现一个接口,但是两者不可兼得;
- 匿名内部类中是不能定义构造函数的;
- 匿名内部类中不能存在任何的静态成员变量和静态方法;
- 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效;
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。