如果内部 class 扩展外部 class,内部 class 的不同成员行为?
Different member behaviour of inner class if inner class extends outer class?
今天我偶然发现了一些奇怪的内部(非静态)class 行为。
如果我有以下 classes ...
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 扩展外部 class 这不起作用。
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 实例。
我觉得这很奇怪...有人可以解释为什么会有这种差异吗?
val
in InheritedB
是指来自其 base class (super.val
) 的 val
,因为那是 this
.
的一部分
如果不从外层class继承,val
指的是外层class的作用域(B.this.scope
)。但是,由于您继承,this
的范围更近,因此隐藏了外部范围。
由于您从未在内部 this
上调用 run()
,this.val
仍然是 old
.
If I have a look at the constructors I also see that a new instance of B will be created if instance of InheritedB is created.
是;创建派生 class 将始终创建其基础 class 的实例。无法从现有实例继承。
这一行:
new InheritedB().printVal();
创建 InheritedB
的新实例,其包含实例是 B
的现有实例(其中 val 是 "new"
)。但是此时有两个val
个变量:
B
的现有实例中的那个
InheritedB
实例中的一个,它有一个单独的 val
字段
第二个变量的值为 "old"
,因为这实际上是该字段的默认值。
InheritedB
中的这条语句:
System.out.println(val + " "+ B.this.val);
打印出继承自B
的val
的值,后面是"containing instance".
中的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();
希望您能准确了解那里发生的事情。编译器 粗略地 将您的原始代码执行到该代码中。
因为 InheritedB extends B
,创建 InheritedB 的实例会授予它一个 val
属性,对于任何 new B,默认情况下是 "old" class 或子class 实例。
这里,InheritedB
打印 它自己的 val
属性,而不是封闭的 B 实例之一。
在 InheritedB
的情况下,有两个变量称为 val
,一个是 B
,另一个是 InheritedB
。应用可见性规则给出观察到的结果。
区别是class InnerB
里面没有成员val
。其中 class InheritedB
扩展 class B 并拥有自己的 val
成员副本。
void run(){
val = "new"; //<--- modifies B's val not InheritedB's val
System.out.println(val); // outputs: new
new InnerB().printVal(); // outputs: new
new InheritedB().printVal(); // outputs: old new
}
在上面的代码块中,InnerB 的 printVal 访问容器的 val
成员,该成员的值已在 run
方法中修改为值 new。
但是InheritedB的对象中val的副本仍然是“old”值,没有修改,printVal函数使用那个值。
今天我偶然发现了一些奇怪的内部(非静态)class 行为。
如果我有以下 classes ...
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 扩展外部 class 这不起作用。
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 实例。
我觉得这很奇怪...有人可以解释为什么会有这种差异吗?
val
in InheritedB
是指来自其 base class (super.val
) 的 val
,因为那是 this
.
如果不从外层class继承,val
指的是外层class的作用域(B.this.scope
)。但是,由于您继承,this
的范围更近,因此隐藏了外部范围。
由于您从未在内部 this
上调用 run()
,this.val
仍然是 old
.
If I have a look at the constructors I also see that a new instance of B will be created if instance of InheritedB is created.
是;创建派生 class 将始终创建其基础 class 的实例。无法从现有实例继承。
这一行:
new InheritedB().printVal();
创建 InheritedB
的新实例,其包含实例是 B
的现有实例(其中 val 是 "new"
)。但是此时有两个val
个变量:
B
的现有实例中的那个
InheritedB
实例中的一个,它有一个单独的val
字段
第二个变量的值为 "old"
,因为这实际上是该字段的默认值。
InheritedB
中的这条语句:
System.out.println(val + " "+ B.this.val);
打印出继承自B
的val
的值,后面是"containing instance".
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();
希望您能准确了解那里发生的事情。编译器 粗略地 将您的原始代码执行到该代码中。
因为 InheritedB extends B
,创建 InheritedB 的实例会授予它一个 val
属性,对于任何 new B,默认情况下是 "old" class 或子class 实例。
这里,InheritedB
打印 它自己的 val
属性,而不是封闭的 B 实例之一。
在 InheritedB
的情况下,有两个变量称为 val
,一个是 B
,另一个是 InheritedB
。应用可见性规则给出观察到的结果。
区别是class InnerB
里面没有成员val
。其中 class InheritedB
扩展 class B 并拥有自己的 val
成员副本。
void run(){
val = "new"; //<--- modifies B's val not InheritedB's val
System.out.println(val); // outputs: new
new InnerB().printVal(); // outputs: new
new InheritedB().printVal(); // outputs: old new
}
在上面的代码块中,InnerB 的 printVal 访问容器的 val
成员,该成员的值已在 run
方法中修改为值 new。
但是InheritedB的对象中val的副本仍然是“old”值,没有修改,printVal函数使用那个值。