今天我偶然发现了一些奇怪的内部(非静态)类行为.
如果我有以下课程......
class B { String val = "old"; void run(){ val = "new"; System.out.println(val); // outputs: new new InnerB().printVal(); // outputs: new } private class InnerB { void printVal(){ System.out.println(val); } } } new B().run();
......一切似乎都很清楚.InnerB的实例属于B的实例,因此如果它应该输出val,则打印已经替换的值'new'.
但是如果内部类扩展了外部类,则这不起作用.
class B { String val = "old"; void run(){ val = "new"; System.out.println(val); // outputs: new new InnerB().printVal(); // outputs: new new InheritedB().printVal(); // outputs: old new } private class InnerB { void printVal(){ System.out.println(val); } } private class InheritedB extends B{ void printVal(){ System.out.println(val + " "+ B.this.val); } } } new B().run(); // outputs: new new old!
如果我查看构造函数,我还会看到如果创建了InheritedB的实例,将创建一个新的B实例.
我发现这很奇怪......有人可以解释为什么会有这种差异吗?
这一行:
new InheritedB().printVal();
创建一个新实例InheritedB
,其实例是B
(其中val是"new"
)的现有实例.但此时有两个 val
变量:
现有实例中的一个 B
实例中的一个InheritedB
,具有单独的val
字段
第二个变量的值是"old"
因为它实际上是字段的默认值.
本声明InheritedB
:
System.out.println(val + " "+ B.this.val);
打印出val
继承自的值B
,后跟val
"包含实例"中的值.
可以更简单地认为它被重构为:
public class B { String val = "old"; } public class InheritedB extends B { B other; public InheritedB(B other) { this.other = other; } void printVal() { System.out.println(val + " "+ other.val); } }
然后你基本上运行:
B original = new B(); original.val = "new": InheritedB inherited = new InheritedB(original); inherited.printVal();
希望你能完全按照那里发生的事情.编译器大致将原始代码执行到该代码中.
val
in InheritedB
指的val
是它的基类(super.val
),因为那是它的一部分this
.
如果不从外部类继承,val
则从外部类(B.this.scope
)引用作用域.但是,由于您继承,this
因此范围更近,因此隐藏了外部范围.
既然你从未打过run()
内心this
,那this.val
还是old
.
如果我查看构造函数,我还会看到如果创建了InheritedB的实例,将创建一个新的B实例.
是; 创建派生类将始终创建其基类的实例.无法从现有实例继承.
因为InheritedB extends B
,创建一个InheritedB实例会授予它一个val
属性,默认情况下,该属性对于任何新的 B类或子类实例都是"旧的" .
在这里,InheritedB
打印自己的 val
属性,而不是封闭的B实例之一.