在Java中,如果我有一个像这样的类
abstract class TestClass
{
int mMember = 0;
int getMember()
{
return mMember;
}
}
以及扩展此类的类:
class TestExtended extends TestClass
{
int mMember = 1;
}
如果我创建一个TestExtended实例,并调用 testExtended.getMember(); 它会返回0还是1?
换句话说,当我扩展一个类,并且不覆盖所述类中的方法时,它是否调用该方法并对所述类或扩展类中的成员进行操作?
我是否需要在扩展类中重新实现(复制粘贴)函数以使函数返回1?
答案 0 :(得分:2)
它将返回0
,而不是1
。
这是因为您无法“覆盖”超类中的字段。您可以设置它们,只要它们不是private
,但如果您声明一个具有相同名称的新变量,它将只是遮蔽超类变量。
另一方面,你可以覆盖方法。
现在,以这种方式遮蔽成员变量通常是一个非常糟糕的想法,并且是避免公共字段的另一个原因。这就是原因:
TestExtended sub = new TestExtended();
sub.mMember = 5;
System.out.println(sub.mMember); // prints '5', as expected
TestClass sup = sub; // this is fine, TestExtended extends TestClass
System.out.println(sup.mMember); // prints '0'!
编译器将根据编译时类型选择要使用的变量版本,从而打破多态性。不要隐藏成员变量,并避免公共字段,这将永远不会有问题。改为使用getter和setter。
答案 1 :(得分:1)
可以通过跑步来确认。它将返回0
。这是因为无法覆盖这些字段。你实际做的是按照jls hiding
实例变量。
覆盖方法不同于隐藏字段(§8.3),因为它是 允许字段隐藏其他类型的字段。
检查例8.4.8.3-4。在language specification获取更多信息
要获得子类版本,您必须:
class TestExtended extends TestClass
{
int mMember = 1;
@Override
int getMember(){
return mMember;
}
}
答案 2 :(得分:0)
基类方法无法访问子类字段(至少不使用反射)。完全停止。
此外,与方法不同,字段不参与覆盖。
答案 3 :(得分:0)
使用testExtended.getMember();
显然意味着您正在调用抽象类方法,因为您不会覆盖子类中的方法。如果你要覆盖它,那么如果你的对象属于类的子类,那么首先会给出子类方法的首选项。所以在这种情况下,除非你覆盖方法,否则它会给你0。