Java 当您执行一件事时,实例变量调用是如何工作的=new B();其中B是a的一个子类?

Java 当您执行一件事时,实例变量调用是如何工作的=new B();其中B是a的一个子类?,java,Java,这可能在某个地方得到了回答,但我不知道该搜索什么。假设你有以下几点 超类,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

这可能在某个地方得到了回答,但我不知道该搜索什么。假设你有以下几点

超类,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(…)
call调用他上一个父母的原始方法

但当我们来到田野时,情况就不同了。如果子类声明了一个新字段,该字段的名称与父类中的字段完全相同,那么它将只隐藏父类的字段而不重写,就像局部变量隐藏全局字段一样。因此,子方法只会看到子方法的字段,但是父方法将继续看到父方法的字段,并且子方法的字段在父类中无论如何都不可见-这就是您得到的

子项可以通过
((父项)此项)访问其父项的字段。字段

详细回答:

所以你要做的就是这样定义Lion:

public class Lion extends Animal {
  public Lion() {
     noise = "ROAR!!";
  }
}
现在,对于Lion实例,Animal的noise成员变量已更新为ROAR


当然,你(几乎)永远不会在像野外那样的类上拥有一个公共可变成员。

你不能覆盖字段,新的
noise
声明在
Lion
中隐藏了父类的
noise
属性。这样做:

public class Lion extends Animal {

//    public String noise = "ROAR!!";  // <---- Remove this line

    public Lion() {
        noise = "ROAR";
    }

    public String toString() {
        return noise;
    }
}
公共类动物{

//public String noise=“ROAR!!”;//默认情况下,java中的所有非静态方法都是有效的。除非它们被标记为final(这使得该方法不可重写).Java使用a来调用正确的对象的方法。

这是因为Java只谈到方法的重写。成员变量只能在子类中隐藏。因此,当您说c.noise时,它实际上将父类中的字符串变量称为c if引用类型动物。

您感兴趣的主题是基本上,根据设计,Java允许重写方法(假设它们是非最终的)JVM将在运行时执行适当的实现。此多态属性仅提供给方法。良好的OO设计将规定字段无论如何都要封装。

我不是Java专业人士,所以我不会将此称为答案,但区别在于Java中的方法是虚拟的。也就是说,当您调用c.toString()时,Java通过使用查找表知道正确使用的方法是Lion's toString()。但是,这种虚拟化不会发生在实例变量上。大多数人在说“类方法/字段”时指的是静态方法/字段,但我很确定您在这里指的是实例方法/字段。