最近读《Effective Java》,其中描述了嵌套类的几种类别:
1.静态成员类。他只是位于某个内里而已,与外部类没有一毛钱关系。
2.非静态成员类。相当于外部类的成员,使用依赖于外部类的实例。
3.匿名类。如:Comparator,Runnable,Thread等。
4.局部类。位于方法内部,相当于方法的局部变量。
比较难理解的是局部类:
1.不能有public、private、protected修饰,好理解,局部变量也是没有这些修饰符的。
2.不能含有静态成员。内部类的实例对象是外部类的对象的一个成员,若没有外部对象,内部对象也是不存在的,何谈静态成员。
3.局部内部类只能访问final局部变量。你如果访问了非final变量,编译器会提示你将变量声明为final。局部变量的生命周期与局部内部类的对象的生命周期的不一致。局部变量当所处的函数执行结束后就已经死亡了,不存在了,但是局部内部类对象还可能一直存在(只要有人还引用该对象),这是就会出现了一个悲剧的结果,局部内部类对象访问一个已不存在的局部变量。那么,编译器是怎么实现的呢?编译器会将外部的final变量在编译阶段就作为内部类的成员变量写入内部类中,如下例子:
原始类:
public class S2 {
public void outerDoSomething() {
final String localObj = "hello";
class InnerClass {
public void innerDoSomething() {
String a = localObj;
System.out.println(a);
}
};
InnerClass innerObj = new InnerClass();
innerObj.innerDoSomething();
}
public static void main(String[] args) {
S2 s2 = new S2();
s2.outerDoSomething();
}
}
编译后的class文件:
public class S2 {
public S2() {
}
public void outerDoSomething() {
String localObj = "hello";
class InnerClass {
InnerClass() {
}
public void innerDoSomething() {
String a = "hello";
System.out.println(a);
}
}
InnerClass innerObj = new InnerClass();
innerObj.innerDoSomething();
}
public static void main(String[] args) {
S2 s2 = new S2();
s2.outerDoSomething();
}
}
所以访问外部的final变量,在编译器就放入内部类了,与外部无关。所以访问安全。
4.静态方法内的方法内部类。
静态方法是没有this引用的,因此在静态方法内的内部类遭受同样的待遇,即:只能访问外部类的静态成员,但可以不是final的,static修饰后就不受实例的束缚,取得静态成员变量了。