实例内部类 | 静态内部类 | 局部内部类 | |
---|---|---|---|
主要特征 | 内部类的实例引用特定的外部类的实例 | 内部类的实例不与外部类的任何实例关联 | 可见范围是所在的方法 |
可用的修饰符 | 访问控制修饰符,abstract, final | 访问控制修饰符,static, abstract, final | abstract, final |
可以访问外部类的哪些成员 | 可以直接访问外部类的所有成员 | 只能直接访问外部类的静态成员 | 可以直接访问外部类的所有成员,并且只能访问所在方法的 final 类型的变量和参数 |
拥有成员类型 | 只能拥有实例成员 | 可以拥有静态成员和实例成员 | 只能拥有实例成员 |
外部类如何访问内部类的成员 | 必须通过内部类的实例来访问 | 对于静态成员,可以通过内部类的完整类名来访问 | 必须通过内部类的实例来访问 |
内部类:定义在类结构中的另一个类,编译后,每个内部类都会生成对应的 .class 文件
四种内部类:
- 实例内部类:没有使用
static
修饰的内部类,OuterClass$InnerClass. class - 静态内部类:使用
static
修饰的内部类,OuterClass$InnerClass. class - 局部内部类:在方法中定义的内部类,OuterClass$NInnerClass. class(增加了一个数字 N,用于区分在不同方法中定义的同名的局部内部类)
- 匿名内部类:没有名称的局部内部类,适合只需要使用一次的类,OuterClass$N
- 实例内部类:没有使用
特点:
- 实例内部类不能含有 static 的变量和方法
- 静态内部类(嵌套类)不能访问外部类的非 static 成员
- 局部内部类及匿名内部类对象不能使用该内部类所在方法的非 final 局部变量
匿名内部类
- 在定义匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用
- 匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口
- 匿名内部类不能定义构造器,不能是抽象类
- 被匿名内部类访问的局部变量必须使用
final
修饰(从 Java 8 开始,被匿名内部类访问的局部变量自动使用了 final 修饰)
定义格式
// 下面代码其实是创建了一个对象
new 实现接口() 或 父类构造器([实参列表]) {
// 匿名内部类的类体部分
}
// 定义匿名内部类继承 Animal,并创建这个类匿名对象
new Animal() {
};
// 定义匿名内部类继承 Bird,并创建这个类匿名对象,之后调用 fly 方法
new Bird() {
public void fly() {
System.out.println("飞翔");
}
}.fly();
// 定义匿名内部类实现 IWalkable,并创建这个类匿名对象,之后调用 walk 方法
new IWalkable() {
@Override
public void walk() {
System.out.println("走路");
}
}.walk();
// 外部类
class Outer {
String str1 = "Outer 实例变量";
static String str2 = "Outer 类变量";
// 实例内部类
class Inner1 {
String str1 = "Inner1 实例变量";
final static String str2 = "Inner1 类变量"; // 实例内部类中不能定义类成员,除非使用 final 修饰
public void doWork() {
String str1 = "Inner1 局部变量";
System.out.println(str1); // Inner1 局部变量
System.out.println(this.str1); // Inner1 实例变量
System.out.println(Outer.this.str1); // Outer 实例变量
}
}
// 静态内部类
static class Inner2 {
String str1 = "Inner2 实例变量";
static String str2 = "Inner2 类变量";
public void doWork() {
String str1 = "Inner2 局部变量";
System.out.println(str1); // Inner2 局部变量
System.out.println(this.str1); // Inner2 实例变量
// System.out.println(Outer.this.str1); // 无法访问外部类的非静态成员
System.out.println(Outer.str2); // Outer 类变量
}
}
public void doWork() {
final String STR3 = "方法中局部变量";
// 局部内部类
class Inner3 {
String str1 = "Inner3 实例变量";
// static String str2 = "Inner3 类变量"; // 局部内部类中不能定义类成员
public void innerDoWork() {
String str1 = "Inner3 局部变量";
System.out.println(str1); // Inner3 局部变量
System.out.println(this.str1); // Inner3 实例变量
System.out.println(STR3); // 被局部内部类访问的局部变量必须使用final修饰
// System.out.println(Outer.this.str1); // 无法访问外部类的非静态成员
System.out.println(Outer.str2); // Outer 类变量
}
}
new Inner3().innerDoWork(); // 只能在局部内部类所在的方法中创建对象
}
}
// 测试类
class InnerClassDemo {
public static void main(String[] args) {
// 通过外部类对象创建实例内部类对象
Outer.Inner1 in1 = new Outer().new Inner1();
in1.doWork();
// 创建一个静态内部类对象不需要外部类对象
// 直接调用静态内部类的构造器创建对象,需用完整的类名
Outer.Inner2 in2 = new Outer.Inner2();
in2.doWork();
new Outer().doWork();
}
}