1. 合乎只在一个地方备用的逻辑:
如果一个类仅仅被一个别的类使用,那么把这个类嵌入到使用它的类中非常符合逻辑,嵌套这样的 帮助类
是的package变得简洁。
2. 有益于封装:
如果两个类A和B,如果B需要访问A定义为private的成员,那么B嵌套到A类中,即使A的成员是private的B也可以访问,另外B类也可以被隐藏起来,不被外部访问。
3. 可读性好且易于维护
在顶级类中在使用它们的地方嵌套很多小的类利于可读和维护
像类变量和类方法一样,静态内部类通过它的 封闭类 来调用。并且像类方法一样,静态内部类不能直接访问定义在外部类的实例变量和实例方法,只能通过外部类的对象引用才可以使用它们。
静态内部类使用外部类或者其他类的实例成员,需要像其他顶级类一样使用它们。静态内部类的行为看起来像是一个顶级类一样,只是仅仅因为包装便利的关系,才将它嵌套到另一个顶级类内部。
静态内部类需要使用它的包装类来访问。
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
像实例变量和实例方法一样,内部类需要通过它的 封闭类的实例 来调用,并且它可以直接访问对象的方法和字段,因为内部类是通过外部类的实例关联,因此它不能定义静态的成员。
内部类的实例要依托于它的外包类的实例存在
class OuterClass { ... class InnerClass { ... } }
要实例化内部类必须实例化外部类,然后在外部类实例的基础上创建内部类:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
如果定义一个类型(比如成员变量或者参数名称)在一个特定的区域(比如内部类或者方法参数)和封闭区域内的另一个定义重名,那么这个定义会 隐匿 掉封闭区域的定义,你无法仅仅通过名字来使用被隐匿掉的定义,可以看如下代码
public class ShadowTest { public int x = 0; class FirstLevel { public int x = 1; void methodInFirstLevel(int x) { System.out.println("x = " + x); System.out.println("this.x = " + this.x); System.out.println("ShadowTest.this.x = " + ShadowTest.this.x); } } public static void main(String... args) { ShadowTest st = new ShadowTest(); ShadowTest.FirstLevel fl = st.new FirstLevel(); fl.methodInFirstLevel(23); } }
输出如下:
x = 23 this.x = 1 ShadowTest.this.x = 0
这个例子定义了三个名字为 x
的变量,ShadowTest类的成员变量x,内部类FirstLevel类的成员变量x,和methodInFirstLevel方法的参数x。methodInFirstLevel方法的参数x隐匿了内部类FirstLevel类的成员变量x,因此你在methodInFirstLevel方法中使用x时使用的是方法参数的x,为了使用内部类FirstLevel的成员变量x,你需要this关键字来指明是内部类FirstLevel类的成员变量x:
System.out.println("this.x = " + this.x);
为了使用更大范围的成员变量,你需要通过指定类名的方式,在此例子中,你在methodInFirstLevel中使用ShadowTest类的成员变量你需要如下做:
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
强烈建议不需要序列化内部类,包括本地类和匿名类。因为编译器编译某些构造器是比如内部类,会创建合成构造,由类,方法,字段和其他与源码不对应的构造器组成。合成构造可以在不更改jvm的前提下实现新的java特性,但是合成构造在不同的编译器下的实现也不通,也就是说生成的.class文件都是不同,因此序列化内部类后,由不同的JRE反序列化时就会出现问题。