当你查看the tutorial 之类的东西时,你可能会发现类似这样的句子
当从同一个类蓝图创建多个对象时,它们每个都有自己不同的实例变量副本。
注意它说的是变量,而不是成员。但即使这样也过于简单化了。这实际上意味着,对象可以有不同的实例变量值。变量的定义(包括注释及其值)是不变的,将它们复制到对象会导致毫无意义的相同副本。
同样,方法的声明,包括它们的代码,都是不变的,因此,复制它们是没有意义的。但是对实例进行操作的方法的有效行为可能会有所不同,因为它们可能对不同的值进行操作。
这同样适用于内部类。它们的定义是不变的,不需要复制它们。但是非静态内部类实例与可能具有不同字段值的外部实例相关联,可能会导致内部类方法的不同行为。
在您的示例中,外部类中没有实例字段,内部类中没有方法,具体取决于外部对象的状态,因此您使用哪个外部实例来实例化内部类对象没有区别(除了一些对垃圾收集的影响很小)。
当您将状态添加到外部实例并将依赖行为添加到内部时,情况会发生变化:
public class Outer {
boolean even;
Outer(boolean even) {
this.even = even;
}
class Inner {
@Override
public String toString() {
return even? "Even": "Odd";
}
}
public static void main(String[] args) {
Inner i1 = new Outer(true).new Inner();
Inner i2 = new Outer(false).new Inner();
System.out.println(i1);
System.out.println(i2);
}
}
这里,两个Inner 实例由于用于创建它们的外部对象而表现出不同的行为。不过,这并不意味着复制了类定义。
从 JDK 16 开始,您将能够向内部类添加静态成员。在这一点上,重要的是不要为每个外部实例复制内部类,换句话说,内部类的静态成员在运行时中只存在一次,就像顶级静态成员或嵌套静态类一样。
例如我们将能够将示例更改为
public class Outer {
boolean even;
Outer(boolean even) {
this.even = even;
}
class Inner {
static {
System.out.println("Inner initialized");
}
@Override
public String toString() {
return even? "Even": "Odd";
}
}
public static void main(String[] args) {
Inner i1 = new Outer(true).new Inner();
Inner i2 = new Outer(false).new Inner();
System.out.println(i1);
System.out.println(i2);
}
}
这将适用于 JDK 16 及更高版本,并且只打印一次“内部初始化”,而不是两次。