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 dtak naprawdę odnosi się do Dogobiektu”, 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 dfaktycznie odnosi się do obiektu, Animala nie do Dogobiektu, 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ć instanceoftestu, 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 animaljest, ż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.