我有一个简单的程序如下:
class Foo {
private final String str = getClass().getSimpleName();
protected void print(){
System.out.println(str);
}
}
class Bar extends Foo {
private final String str = getClass().getSimpleName();
@Override
protected void print(){
super.print();
System.out.println(str);
}
}
class FooBarMain {
public static void main(String[] args){
Foo foo = new Foo();
foo.print();
Foo foobar = new Bar();
foobar.print();
Bar bar = new Bar();
bar.print();
}
}
输出:
富
酒吧
酒吧
酒吧
酒吧
输出不应如下?
富
富
酒吧
富
酒吧
查看输出,似乎str
已在派生类中被覆盖。但,
str
是最终的并且是私密的。它无法被覆盖。谁能帮我?
答案 0 :(得分:5)
这很简单,实际上:您使用getClass()
表示this.getClass()
。如果您实例化Bar
,那么getClass()
将返回课程Bar
- 无论是在Foo
还是在Bar
中调用:无论如何,该课程为{{ 1}}。
答案 1 :(得分:3)
并不是str
被覆盖了。它只是在构造对象时计算出来的。您的Bar
类有两个不同的str
值,每个值都是在使用getClass().getSimpleName();
初始化对象时确定的。
即使super.print()
中的Bar
引用str
类中的Foo
,该值仍然使用getClass()
方法初始化Bar
对象。
实际运行代码后,getClass()
并不关心您是否在Foo
类声明中编写了代码。它只知道对象的实际类在评估时是什么。
来自getClass
返回此Object的运行时类。返回的Class对象是由所表示的类的静态同步方法锁定的对象。
由于您的方法不是静态的,因此在构造对象时会对其进行求值,而不是在声明类时进行求值。在那个时间点,Bar
是Bar
,因此为了遵守它所承诺的合同,getClass
需要返回Bar.class
。
答案 2 :(得分:2)
获得预期输出的最简单方法就是
class Foo {
private final String str = "Foo";
protected void print(){
System.out.println(str);
}
}
class Bar extends Foo {
private final String str = "Bar";
@Override
protected void print(){
super.print();
System.out.println(str);
}
}
getClass()
没有按你的想法行事。它不返回行getClass
出现的类,它返回实例的实际运行时类型。因此,如果使用new Bar()
对象进行实例化,getClass()
将总是给您Bar.class
即使代码出现在Foo
中,即使编译也是如此变量的时间类型为Foo
(如Foo fooBar = new Bar();
示例中所示)。
答案 3 :(得分:-2)
Bar中的成员str隐藏了Foo中的成员,所以如果你有一个Bar对象,它将始终打印“Bar”。保存对象句柄的变量类型无关紧要,无论类型是Foo还是Bar,无论何时创建Bar,它都是Bar,无论您将其视为Bar,Foo还是Object。