Question about Java polymorphism and casting

后端 未结 9 2268
谎友^
谎友^ 2020-12-29 12:02

I have a class C. Class E extends it.

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

Why is

e = (E) c;

Upon further review

相关标签:
9条回答
  • 2020-12-29 12:12

    the int/double is unrelated; that is a conversion, not a cast - there is no relationship between int and double.

    Re the question; a type's object is fixed at creation. An object that is a C is not (and can never be) an E. However, you can treat an E as a C, since inheritance represents "is a". For example:

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

    Here we still only have one object - simply that the c variable thinks of it as a C, so won't expose methods specific to E (even though the object is an E).

    If we then add:

    E secondE = (E) c;
    

    This is a type check; again, we haven't changed the object, but to put c into an E variable requires us to prove to the compiler/runtime that it really is an E. We didn't need this in the first example as it can already prove that any E is also a C.

    Likewise, with the getClass() - all the cast does is change how the compiler thinks of the object; you haven't changes the object itself. It is still a K.

    You need to separate variables from objects. The cast is talking about the variables; they don't change the object.

    0 讨论(0)
  • 2020-12-29 12:13

    Consider a real-world example:

    public class Dog extends Animal
    

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

    public class Cat extends Animal
    

    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() gives K. Why is that? It was casted to the more general M!

    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.

    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.


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

    ((M) k).doIt();

    gives M's or K's 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.


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

    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() );
             }
         }
    }
    
    0 讨论(0)
  • 2020-12-29 12:16

    You can't cast objects in Java.

    You can cast references in Java.

    Casting a reference doesn't change anything about the object it refers to. It only produces a reference of a different type pointing to the same object as the initial reference.

    Casting primitive values is different from casting references. In this case the values do change.

    0 讨论(0)
  • 2020-12-29 12:22

    "If the compiler treats it as an M, it should execute M's methods."
    The compiler treats the reference as M. The instance that the reference points to is of type K, not M. You can't cast the reference and assume that means the instance will suddenly change behavior. What the compiler does is make sure that the method you invoke on the specified reference exists. It does not have anything to do with which implementation is invoked, only that an implementation does exist.

    0 讨论(0)
  • 2020-12-29 12:25

    To add to Frederik's answer, casting an object to something doesn't change it's type. Also, object's can only be cast to a type it already is (the compiler just doesn't know at that point) That's why impossible casts will never be accepted:

    Integer i = (Integer) new String();
    

    will not compile, because the compiler knows it can't be possible.

    0 讨论(0)
  • 2020-12-29 12:32

    Casting an object does not change the object to the object being cast, but allows another class reference that is related to it by inheritance to refer to the object.

    For example C extends E. And they both have a method myName();. If you say

    E e = new C();
    e.myName();
    

    you are calling C myName() method and if you also say

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

    you just told the compiler that it should allow you refer to E with C reference type.

    0 讨论(0)
提交回复
热议问题