Opracowanie odpowiedzi udzielonej przez Michaela Berry'ego.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Tutaj mówisz do kompilatora „Zaufaj mi. Wiem, że d
tak naprawdę odnosi się do Dog
obiektu”, chociaż tak nie jest.
Pamiętaj, że kompilator jest zmuszony nam zaufać, kiedy robimy upadek .
Kompilator wie tylko o zadeklarowanym typie referencyjnym. JVM w czasie wykonywania wie, czym naprawdę jest obiekt.
Więc kiedy JVM w środowisku wykonawczym zorientuje się, że Dog d
faktycznie odnosi się do obiektu, Animal
a nie do Dog
obiektu, mówi. Hej ... okłamałeś kompilatora i wyrzuciłeś duży tłuszcz ClassCastException
.
Więc jeśli jesteś przygnębiony, powinieneś użyć instanceof
testu, aby uniknąć schrzanienia.
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
Teraz przychodzi nam do głowy pytanie. Dlaczego piekielny kompilator pozwala na upadek, skoro w końcu wyrzuci java.lang.ClassCastException
?
Odpowiedź jest taka, że wszystko, co może zrobić kompilator, to sprawdzić, czy oba typy są w tym samym drzewie dziedziczenia, więc w zależności od tego, jaki kod mógł pojawić się przed obniżeniem, możliwe animal
jest, że jest to typ dog
.
Kompilator musi zezwalać na rzeczy, które mogą działać w czasie wykonywania.
Rozważ następujący fragment kodu:
public static void main(String[] args)
{
Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
d.eat();
}
private static Animal getMeAnAnimal()
{
Animal animal = new Dog();
return animal;
}
Jeśli jednak kompilator jest pewien, że rzutowanie nie będzie możliwe, kompilacja zakończy się niepowodzeniem. IE Jeśli spróbujesz rzutować obiekty w różnych hierarchiach dziedziczenia
String s = (String)d; // ERROR : cannot cast for Dog to String
W przeciwieństwie do downcastingu, upcasting działa niejawnie, ponieważ podczas upcastingu pośrednio ograniczasz liczbę metod, które możesz wywołać, w przeciwieństwie do downcasting, co oznacza, że później możesz chcieć wywołać bardziej szczegółową metodę.
Dog d = new Dog();
Animal animal1 = d; // Works fine with no explicit cast
Animal animal2 = (Animal) d; // Works fine with n explicit cast
Oba powyższe uniesienia będą działać dobrze bez żadnych wyjątków, ponieważ Pies JEST Zwierzęciem, niezależnie od tego, co może zrobić Zwierzę, może to zrobić pies. Ale to nieprawda, odwrotnie.