我无法理解继承。在下面的代码中,为什么继承的方法不访问子类中的字段?有没有办法在不重写继承方法的情况下访问子类字段?
class Fish {
private String fishType = "Fish";
public String getFishType() {
return fishType;
}
}
class Marlin extends Fish {
private String fishType = "Marlin";
}
public class InheritanceTest {
public static void main(String[] args) {
Fish fish1 = new Fish();
Fish marlin1 = new Marlin();
System.out.println(fish1.getFishType());
System.out.println(marlin1.getFishType());
}
}
此代码打印
Fish
Fish
但我期待
Fish
Marlin
每个人似乎都在根据私有字符串回答,但即使我将字段更改为公开,我仍然有问题。问题不在于继承私人领域。
请参阅下面的更新代码。
class Fish {
public String fishType = "Fish";
public String getFishType() {
return fishType;
}
}
class Marlin extends Fish {
public String fishType = "Marlin";
}
public class InheritanceTest {
public static void main(String[] args) {
Fish fish1 = new Fish();
Marlin marlin1 = new Marlin();
System.out.println(fish1.getFishType());
System.out.println(marlin1.getFishType());
}
}
输出和我的期望与上述相同。
答案 0 :(得分:4)
首先,private
的字段(和方法)不继承。您的Marlin
班级甚至不知道其父级字段。
其次,Java将根据您在运行时使用的实例选择最合适的方法进行调用。由于Marlin
没有定义方法getFishType
,因此它将使用其父项'方法
你可以采取几种方法;其中一个覆盖getFishType
内的Marlin
方法:
@Override
public String getFishType() {
return fishType;
}
使用新代码,您可以通过在Marlin
内重新声明来实际hiding the variable。
如果类声明了一个具有特定名称的字段,那么该字段的声明将被隐藏为隐藏超类中具有相同名称的字段的任何和所有可访问声明,以及该类的超接口。
通过不重新声明变量,可以轻松解决这个问题;相反,在施工时分配你想要的值。
public Marlin() {
fishType = "Marlin";
}
或者,为了使代码更清晰,您可以使用父方法重构您的类,而不是在子代中重写它。这确实需要父类中的几个构造函数。
class Fish {
private final String fishType;
// Default constructor; used in nominal cases
public Fish() {
this("Fish");
}
// Constructor used to populate the fishType field
public Fish(final String fishType) {
this.fishType = fishType;
}
public String getFishType() {
return fishType;
}
}
class Marlin extends Fish {
public Marlin() {
super("Marlin"); // invoke super's constructor
}
}
再一次,由于getFishType
中没有合适的方法Marlin
,它会查找Fish
类并改为使用其方法。然而,这一次,我们实际想要达到的价值是我们期望的价值。
答案 1 :(得分:1)
你必须在Marlin课程中覆盖getFishType()
。私有财产只在一个类中可见。
答案 2 :(得分:1)
尽管@Makoto给出了一个合理的答案,但我仍未正确回答OP问题的意图。
问题是,为什么在Marlin实例上调用时,继承的fishType
方法不支持在Marlin类中重新声明的getFishType()
。
当您想到方法查找的工作方式(与字段查找相对)有何不同时,这尤其令人好奇:方法Fish::getT()
:protected String getT() {return "Fish";}
,并在Marlin::getT()
中用protected String getT() {return "Marlin";}
覆盖它,并在Fish::getFishType()
中调用此新方法,而不是访问该字段,即对{{ 1}}实际上会产生“马林鱼”。 -在此,子类方法用于继承的方法中,而不是同名的父方法。这是因为方法查找总是从当前实例开始。
我认为答案由@Makoto给出的Java文档中的引号指示:重新声明的字段“隐藏”继承层次结构中所有相同名称的其他可访问声明(而重新声明的方法“覆盖”之前具有相同名称和签名的声明)。我的意思是说marlin1.getFishType()
必须被视为与Marlin.fishType
(偶然使用相同的名称)完全不同的符号。而Fish.fishType
只会看到它自己的版本。
答案 3 :(得分:0)
您应该覆盖getFishType()
,而不仅仅是fishType
。该方法是继承的,但私有属性不是。