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()
是 Animal
和 Dog
的方法,所以它解析,但是它解析到 Dog
上定义的方法,因为 myAnimal
仍然引用 Dog
的一个实例,尽管被向上转换。
我试图理解 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()
是 Animal
和 Dog
的方法,所以它解析,但是它解析到 Dog
上定义的方法,因为 myAnimal
仍然引用 Dog
的一个实例,尽管被向上转换。