关于Java多态和强制转换的问题

2022-01-24 00:00:00 polymorphism casting java

我有一个 C 类.E 类扩展了它.

I have a class C. Class E extends it.

E e = new E();
C c = new C();

为什么

e = (E) c;

经过进一步审查:尽管数字转换与强制转换对象具有相同的语法,但还是出现了一些混淆.无论如何,上面的代码并没有给出编译,而是运行时错误——因此在某些情况下可以将类转换为子类(否则代码将无法编译).任何人都可以举出上述方法的任何例子吗?

Upon further review: though numeric conversions have the same syntax as casting objects, some confusion arose. At any event, the above does not give a compilation, but rather a runtime error - so a class can be casted to subclass in some instances (otherwise the code would not compile). Any examples that anyone can give where the above works?

还有:

K extends M

K k = new K();

((M) k).getClass() 给出 K.这是为什么?它被转换为更通用的 M!

((M) k).getClass() gives K. Why is that? It was casted to the more general M!

假设我在 M 和 K 中都实现了一个 doIt() 方法.执行

Suppose I have a doIt() method implemented in both M and K. executing

((M) k).doIt();

给出 M 或 K 的 doIt()?

gives M's or K's doIt()?

谢谢!

推荐答案

考虑一个真实的例子:

public class Dog extends Animal

所有的狗都是动物,但并非所有的动物都是狗.因此...

All dogs are animals, but not all animals are dogs. Hence...

public class Cat extends Animal

只有当所讨论的动物确实是狗时,才能将动物投给狗.否则,它将迫使宇宙将狗独有的特性(摇尾巴、吠叫等)推断到动物身上.那只动物很可能是一只猫,具有独特的特性(咕噜声、严格的自我清洁机制等).如果无法进行强制转换,则在运行时抛出 ClassCastException.

Casting an Animal to a Dog can only be done if the Animal in question is indeed a Dog. Otherwise it would force the Universe to infer properties unique to a dog (wagging tail, barking, etc.) onto an Animal. That Animal might well be a Cat with properties unique to it (purring, rigorous regime of self-cleaning, etc.). If the cast is not possible then a ClassCastException is thrown at runtime.

没有人想要一只会发出咕噜声的狗.

Nobody wants a dog that purrs.

((M) k).getClass() 给出 K.这是为什么呢?它被投射到更一般的 M 上!

((M) k).getClass() gives K. Why is that? It was casted to the more general M!

您已将 k 强制转换为 M,但所有类都有 getClass() 方法.k 的类始终为 K,无论您是否将其引用投射到 M 中.如果你将 Dog 投射到 Animal 上并问它是什么动物,它仍然会回答它是一只狗.

You've casted k to M, but all classes have a getClass() method. k's class is always K, regardless of whather you cast its reference to M or not. If you cast a Dog to an Animal and ask it what animal it is it'll still answer that it's a dog.

事实上,强制转换为超类是多余的.Dog 已经是 Animal,它拥有 Animal 的所有方法以及它自己的方法.许多代码分析工具(例如 FindBugs)会通知您多余的强制转换,以便您删除它们.

In fact, casting to a superclass is redundant. A Dog already is an Animal and it has all the methods of an Animal as well as its own. Many Code Analysis tools such as FindBugs will notify you of redundant casts so you can remove them.

假设我在 M 和 K 中都实现了一个 doIt() 方法.执行

Suppose I have a doIt() method implemented in both M and K. executing

((M) k).doIt();

((M) k).doIt();

给出 M 或 K 的 doIt()?

gives M's or K's doIt()?

K 的 doIt() 出于与上述相同的原因.演员表对参考进行操作;它不会将对象转换为不同的类型.

K's doIt() for the same reasons as above. The cast operates on the reference; it doesn't transform an object to a different type.

你能举例说明什么时候强制转换 (Dog doggy = (Dog) myAnimal) 是有意义的吗?

Can you give an example of when casting (Dog doggy = (Dog) myAnimal) makes sense?

当然可以.想象一个接收动物列表进行处理的方法.所有的狗都需要带走,所有的猫都需要用鸟形玩具玩耍.为此,我们调用仅存在于 Dog 上的 takeForWalk() 方法,或仅存在于 Cat 上的 play() 方法.

Sure can. Imagine a method that receives a list of animals for processing. All the dogs need to be taken for a walk, and all the cats need to be played with using a bird-shaped toy. To do this we call the takeForWalk() method that only exists on Dog, or the play() method which only exists on Cat.

public void amuseAnimals( List<Animal> animals ) {
    for ( Animal animal : animals ) {
         if ( animal instanceof Dog ) {
             Dog doggy = (Dog)animal;
             doggy.takeForWalk( new WalkingRoute() );
         } else if ( animal instanceof Cat ) {
             Cat puss = (Cat)animal;
             puss.play( new BirdShapedToy() );
         }
     }
}

相关文章