实例变量调用在你做什么时工作A thing = new B();其中B是A的一个子类?
这可能是回答某处,但我不知道要搜索什么。想象一下,你有以下...实例变量调用在你做什么时工作A thing = new B();其中B是A的一个子类?
超类,Animal.java
public class Animal {
public String noise = "squeak";
public String toString() { return noise; }
}
子类,Lion.java
public class Lion extends Animal {
public String noise = "ROAR!!";
public String toString() { return noise; }
}
的主类,Runner.java
public class Runner {
public static void main(String[] args) {
Animal a = new Animal();
System.out.println(a);
System.out.println(a.noise);
Lion b = new Lion();
System.out.println(b);
System.out.println(b.noise);
Animal c = new Lion();
System.out.println(c);
System.out.println(c.noise);
}
}
输出结果为:
squeak
squeak
ROAR!!
ROAR!!
ROAR!!
squeak
c.noise为什么会返回吱吱声?实例方法调用和实例变量之间的区别是什么,它会返回您期望的结果,而另一个则不会?为什么Java会这样做?
感谢
简短的回答:
您可以替代的方法,但它不可能覆盖领域。
龙答:
每个班级看到的方法和它自己和它的父母的领域(除私有方法)。如果孩子在名称相同的情况下删除方法在其父类中的名称,则此方法将变为覆盖 - 如果以某种方式在子实例上调用此方法(即使是从父方法),将使用全新的方法而不是父级的方法。孩子仍然可以通过电话super.method(...)
致电最后一位家长的原始方法。
但是当我们来到田野时,故事是不同的。如果孩子声明了一个新的字段,该字段的名称与父类中的字段完全一样,它将简单地隐藏父类的字段不重写,就像本地变量隐藏全局字段一样。所以子方法只会看到孩子的字段,但父母的方法会继续看到父母的字段,并且父类的任何方式都无法看到孩子的字段 - 这就是你所得到的。
孩子可以通过((Parent)this).field
访问其父母的字段。
当他们说“类方法/字段”时,大多数人的意思是静态方法/字段,但我很确定你是指实例方法/字段。 –
对不起,为了避免含糊不清,更正。 –
较长的答案:
所以真的你会做到这一点的方法是这样定义的狮子:所以现在
public class Lion extends Animal {
public Lion() {
noise = "ROAR!!";
}
}
的狮子实例动物的噪音成员变量已经更新到吼!
当然,你(几乎)从来没有在类似野外的类上实际拥有一个公共可变成员。
您无法覆盖字段,中的noise
的新声明会隐藏父项的noise
属性。像这样:
public class Lion extends Animal {
// public String noise = "ROAR!!"; // <---- Remove this line
public Lion() {
noise = "ROAR";
}
public String toString() {
return noise;
}
}
java中的所有非静态方法默认为"virtual functions"。除非它们被标记为final(这使得方法不可覆盖)。 Java使用virtual method table来调用正确的对象的方法。
这是因为Java只谈约方法覆盖。成员变量只能在子类中映射。所以当你说c.noise时,它实际上是指父类中的字符串变量作为c,如果引用类型为Animal。
您感兴趣的主题有Dynamic Dispatch和Virtual Method Table。基本上,通过设计,Java允许重写方法(假设它们是非最终的),并且在运行时JVM将执行相应的实现。这个多态属性只提供给方法。好的OO设计将决定封装这些字段。
我不是Java专业人员,所以我不会称这为答案,但区别在于Java中的方法是虚拟的。也就是说,当你调用c.toString()时,Java通过使用查找表知道使用正确的方法是Lion的toString()。但是,这种虚拟化不会发生在实例变量上。 – erisco