public class Animal {
public void eat() {}
}
public class Dog extends Animal {
public void eat() {}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = (Dog) animal;
}
}
Przypisanie Dog dog = (Dog) animal;
nie generuje błędu kompilacji, ale w czasie wykonywania generuje plik ClassCastException
. Dlaczego kompilator nie może wykryć tego błędu?
java
casting
classcastexception
saravanan
źródło
źródło
Odpowiedzi:
Używając obsady, zasadniczo mówisz kompilatorowi „zaufaj mi. Jestem profesjonalistą, wiem, co robię i wiem, że chociaż nie możesz tego zagwarantować, mówię ci, że ta
animal
zmienna jest zdecydowanie będzie psem ”.Ponieważ zwierzę w rzeczywistości nie jest psem (to zwierzę, możesz to zrobić
Animal animal = new Dog();
i byłby to pies), maszyna wirtualna zgłasza wyjątek w czasie wykonywania, ponieważ naruszyłeś to zaufanie (powiedziałeś kompilatorowi, że wszystko będzie w porządku i jest nie!)Kompilator jest nieco mądrzejszy niż ślepe akceptowanie wszystkiego, jeśli spróbujesz rzucić obiekty w różnych hierarchiach dziedziczenia (na przykład rzucić psa na łańcuch), kompilator odrzuci to z powrotem, ponieważ wie, że to nigdy nie zadziała.
Ponieważ zasadniczo powstrzymujesz kompilator przed narzekaniem, za każdym razem, gdy rzucasz, ważne jest, aby sprawdzić, czy nie spowodujesz
ClassCastException
użyciainstanceof
w instrukcji if (lub czegoś podobnego).źródło
Dog
nie rozciągają się odAnimal
!Bo teoretycznie
Animal animal
może to być pies:Ogólnie rzecz biorąc, poniżanie nie jest dobrym pomysłem. Powinieneś tego unikać. Jeśli go używasz, lepiej dołącz czek:
źródło
Aby uniknąć tego rodzaju ClassCastException, jeśli masz:
Możesz zdefiniować konstruktor w B, który pobierze obiekt A. W ten sposób możemy wykonać "rzutowanie" np:
źródło
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ę doDog
obiektu”, chociaż tak nie jest. Pamiętaj, że kompilator jest zmuszony nam zaufać, kiedy robimy upadek .Więc kiedy JVM w środowisku wykonawczym zorientuje się, że
Dog d
faktycznie odnosi się do obiektu,Animal
a nie doDog
obiektu, mówi. Hej ... okłamałeś kompilatora i wyrzuciłeś duży tłuszczClassCastException
.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 typdog
.Rozważ następujący fragment kodu:
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
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.
źródło
Kod generuje błąd kompilacji, ponieważ typ instancji to Animal:
Downcasting nie jest dozwolony w Javie z kilku powodów. Zobacz tutaj po szczegóły.
źródło
Jak wyjaśniono, nie jest to możliwe. Jeśli chcesz użyć metody z podklasy, oceń możliwość dodania metody do nadklasy (może być pusta) i wywołaj z podklas uzyskując pożądane zachowanie (podklasę) dzięki polimorfizmowi. Więc kiedy wywołasz d.method (), wywołanie powiedzie się bez rzutowania, ale w przypadku, gdy obiekt nie będzie psem, nie będzie problemu
źródło
Aby opracować odpowiedź @Caumons:
Teraz spójrz na to rozwiązanie.
Teraz testujemy aplikację:
A oto wynik:
Teraz możesz łatwo dodawać nowe pola do klasy ojca, nie martwiąc się o kody dzieci do złamania;
źródło