public class NotActuallyImmutable {
private final int x;
public NotActuallyImmutable(int x) {
this.x = x;// line 1
}
public int getX() {
return x;
}
}
public class Mutable extends NotActuallyImmutable {
private int x = 123;
public Mutable(int x) {
super(x);
}
public int getX() {
return x++;
}
}
现在在我的主要班级
NotActuallyImmutable n = new Mutable(42); // line2
int x = n.getX();
System.out.println("x is"+x);
我期待输出为42,但它将输出返回为123.我期待42,因为在第2行我正在创建类Mutable的对象然后在第1行我将值设置为42.所以当我这样做时{ {1}}我应该得到这个最新的值而不是默认的123.我知道我错过了一些但却无法弄清楚其背后的逻辑吗?
答案 0 :(得分:2)
问题是x
中的字段Mutable
和类x
中的字段NotActuallyImmutable
不一样。 x
返回的getX()
是Mutable
中的getX()
(因为调用的Mutable.getX()
是NotActuallyImmutable.getX()
,而不是Mutable
)。
请注意,如果您从NotActuallyImmutable.x
中删除了实例字段,则会出现编译错误,因为NotActuallyImmutable
对Mutable
是私有的,NotActuallyImmutable.x
中的任何代码都无法访问}。
如果您将Mutable.x
设为受保护字段,那么Mutable.x
会影响它,您仍然会有相同的行为。如果您在这种情况下删除了final
,那么您仍然会遇到编译错误,因为您尝试增加Mutable.getX()
字段。
如果您删除x
,那么getX()
将返回的NotActuallyImmutable.x
将为Mutable
,尽管{{1}中有另一个同名字段}}
答案 1 :(得分:2)
private int x
中的Mutable
和private int x
中的NotActuallyImmutable
是完全不同的字段,只有相同的名称。
这对编译器来说不是问题,因为您无法从另一个类访问private
字段。因此,就编译器而言,当您定义Mutable
时,x
中的NotActuallyImmutable
是不可见的,也可能不存在。
程序员当然会感到困惑。如果您将其中一个字段重命名为y
(并将getter方法重命名为getY
),则行为似乎更直观。
答案 2 :(得分:1)
NotActuallyImmutable n = new Mutable(42); // line2
这意味着您有一个NotActuallyImmutable类型的对象,但创建的对象的实例是Mutable。 所以在这段代码中你处理Mutable对象将返回123.因为你传递的数字保存在NotActuallyImmutable中而不是Mutable中,
答案 3 :(得分:0)
n
有两个不同的x
值,它们在不同的上下文中可见,父类的私有成员变量和子类的私有成员变量。
NotActuallyImmutable n = new Mutable(42); // line2
创建新的Mutable
。执行parent(x)
,将父类的x
设置为42。
int x = n.getX();
n
是Mutable
个实例,因此会调用Mutable
的{{1}},其中getX()
的值为Mutable
(123)而不是父母的。
答案 4 :(得分:0)
我同意上述答案中给出的尼斯解释。但要简要介绍最后的理解。当我正在做新的Mutable(42).getX()时,jvm首先会查看Mutable对象,以获取不在NotActuallyImmutable内的X值。如果我从Mutable中删除了getX()方法,我得到了预期的(按照我的期望)值,即42。
此示例变得混乱becoz变量名称,即父和子类中的X相同但有助于理解概念