Java 派生类的意外行为
我有一个简单的程序如下:Java 派生类的意外行为,java,oop,inheritance,overriding,derived-class,Java,Oop,Inheritance,Overriding,Derived Class,我有一个简单的程序如下: 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(); @Overri
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();
}
}
输出:Foo
酒吧
酒吧
酒吧
酒吧
输出不应该如下所示吗?
Foo
Foo
酒吧
Foo
酒吧
查看输出,似乎
str
已在派生类中被重写。但是
str
是最终的和私有的。它不可能被覆盖。有人能帮我吗 Bar中的成员str隐藏Foo中的成员str,因此如果您有Bar对象,它将始终打印“Bar”。无论变量的类型是什么,无论类型是Foo还是Bar,只要你创建了一个Bar,它就是一个Bar,不管你是将它作为Bar、Foo还是对象来对待。这并不是说str
被覆盖。它只是在构造对象时计算出来的。您的Bar
类有两个不同的str
值,每个值都是在您使用getClass().getSimpleName()初始化对象时确定的代码>
即使Bar
中的super.print()
引用Foo
类中的str
,该值仍然使用Bar
对象的getClass()
方法初始化
一旦您实际运行了代码,getClass()
就不在乎您是否在Foo
类声明中编写了它。它所知道的只是对象在求值时的实际类
从getClass
返回此对象的运行时类。返回的类对象是由所表示类的静态同步方法锁定的对象
由于您的方法不是静态的,因此在构造对象时对其进行计算,而不是在声明类时。在那个时候,Bar
就是一个Bar
,所以为了遵守它承诺的契约,getClass
需要返回Bar.class
这很简单,真的:你使用getClass()
,意思是this.getClass()
。如果实例化Bar
,则getClass()
将返回classBar
——无论是在Foo
中调用还是在Bar
中调用:无论哪种方式,类都是Bar,获得预期输出的最简单方法就是执行以下操作
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();
示例).为什么会被否决?好的..我刚刚用另一个值替换了getClass().getSimpleName(),它可以正常工作。你能简单解释一下getClass()是如何做到这一点的吗?@NathanHughes和resueman谢谢你的解释。是的,我做到了。那很好。我现在明白了。感谢DownVote,因为这是错误的,阴影不起作用,这是因为getClass总是返回具体的类,不管它是从Foo还是从Bar调用的。是的,我同意,特别是如果getClass().getName()只在基类中完成。但是,如果str被硬编码为“Foo”和“Bar”,那么它的行为方式仍然相同,这就是原因。第一句话仍然具有误导性,隐藏与此无关。