Upcasting/Downcasting 在 Java

Upcasting/Downcasting in Java

我试图理解 Java 中的向上转型和向下转型,但我对以下场景(关于我的代码,如下所示)感到困惑:

首先 - 为什么当我包含行 myAnimal.bark();

时代码无法编译

和第二 - (假设我注释掉 myAnimal.bark();)为什么调用 myAnimal.move() 打印 "moveDog" 而不是 "moveAnimal"myAnimal 是否仅限于 Animal class 中的方法,因为我们已将其类型声明为 Animal,即使我们将其设置为 [=21] 的类型=]?

非常感谢任何帮助!这是代码:

    public class Animal {
        public void move() {
            System.out.println("moveAnimal");
        }

       public static void main(String[] args) {
          Dog myDog = new Dog();
          Animal myAnimal = myDog;
          myAnimal.move();
          //myAnimal.bark();
       }
    }

    class Dog extends Animal {
        @Override
        public void move() {
           System.out.println("moveDog");
        }

        public void bark() {
            System.out.println("bark");
        }
    }


这里有两个相互竞争的重要概念。

第一个概念是静态类型,这意味着Java编译器会在编译时检查表达式、变量和方法的类型 ,在代码有机会 运行 之前。在这种情况下,变量myAnimal是类型Animal,而类型Animal没有方法bark(),所以myAnimal.bark()是类型错误。

第二个概念是dynamic dispatch,意思是根据对象的类型选择方法实现在运行时间。由于 myAnimal 持有对 class Dog 对象的引用,因此对 move() 方法的调用会调用 Dog class.

在这里您将 myAnimal 声明为 Animal 并且所有动物都不能吠叫!即 myAnimal 在这里指的是 Animal。

动物 myAnimal = myDog;

但是可以肯定的是,Dog 是一种可以吠叫的动物,因此您需要通过让 JVM 知道它的类型 Dog 而不是 Just Animal 来显式转换 myAnimal。

所以如果你改变 //myAnimal.bark();到下面它会起作用!

((狗) myAnimal).bark();

这里我们将 myAnimal 从 Animal 转换为 Dog。因此 bark() 方法是允许的,它不会给出任何编译问题。

希望对您有所帮助!

在这一行使用隐式向上转换:

Animal myAnimal = myDog;

您没有做任何更改底层实例的事情myDog。您正在做的是将它分配给继承树中更高一级类型的变量。实际上,这限制了只能调用 Animal 中定义的方法,但不会改变这些方法的解析方式。

因为您已将可用的方法限制为仅在父 class Animal 上定义的方法可用,编译器无法解析 Dog#bark(),因为它是 [=15= 的方法],并且变量 myAnimal 被定义为 Animal 类型,它没有 #bark 方法。

#move()AnimalDog 的方法,所以它解析,但是它解析到 Dog 上定义的方法,因为 myAnimal 仍然引用 Dog 的一个实例,尽管被向上转换。