Java 使用两个不同的子类进行向下转型

Java downcasting with two different subclasses

我正在学习 Java 并且一直在使用我在 Eclipse 中定义的 classes 在我的命令提示符中使用向上和向下转换。我正在使用此处包含的三个 classes,我的问题在底部:

public class Animal {
    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

    public void eat() {
        System.out.println("Yummy");

    }

    public void sleep() {
        System.out.println("I like sleep.");
    }

}

public class Mammal extends Animal {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

    public void controlTemp() {
        System.out.println("Temperature regulation ");

    }

}

public class Lion extends Mammal {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

    @Override
    public void sleep() {
        super.sleep();
        System.out.println("Especially on the grass.");
    }
    
    @Override
    public void controlTemp() {
        super.controlTemp();
        System.out.println("I'm an endotherm.");
    }

    public void roar() {
        System.out.println("ROARRRRR!");
    }
}

这是我在 cmd 中使用 jshell 所做的:

jshell> Animal a1 = new Lion();
a1 ==> Lion@4afc40bb
|  created variable a1 : Animal

jshell> ((Mammal)a1).controlTemp();
Temperature regulation
I'm an endotherm.

jshell> ((Lion)a1).controlTemp();
Temperature regulation
I'm an endotherm.

我的问题是为什么将 a1 转换为 Mammal 会给我 Lion class 中覆盖的 controlTemp() 方法的结果,而不是 Mammal class 中的结果?

因为java中的所有非静态方法总是通过一个叫做动态调度.[=26的东西解决=]

更具体地说,什么方法签名你实际上select取决于你调用的东西的类型它在。表达式 ((Mammal) a1)Mammal 类型(不是因为 a1 是狮子;这是因为任何转换为​​ Mammal 的都是 Mammal 类型的表达式)。

但是,对于给定的签名,您得到的实际方法是什么?这完全 取决于表达式引用的实际对象的运行时类型。

在运行时级别,方法不仅有名称:它们的完整签名包括它们的参数类型、名称和 return 类型。

如您的 @Override 注释所示,Lion class 中的 public void controlTemp() 具有相同的名称、相同的参数类型(即:noa 参数)和相同的 return 类型(即:void),因此它 覆盖 Mammal.

中的 void controlTemp() 方法

这使我们进入以下流程:

  • 你 'selected' 在 Mammal 中定义的 controlTemp() 方法,它被编译到你的 class 文件中。换句话说,在编译过程中,都是关于哺乳动物的。这就是表达式的类型。
  • 但是在运行时,这个方法是动态调度的:检查你的 a1 ref 指向的实际对象,发现是 Lion 的实例,并且最具体的版本Lion 的任何实例所具有的 controlTemp 方法的一部分,是在 Lion 中定义的方法。这样一个就被调用了。

那么你如何调用来自动物的那个? 不可能,除非在 public class Lion extends Mammal {} 中,您可以在其中使用 super.controlTemp() 调用它。在其他任何地方,你根本无法这样做(至少,如果没有原始的 class hackery,这远远超出了你所处水平的范围,而且不是任何人用 java-the-language 编写的东西这样做是有充分理由的)。