Jaka jest różnica między rzutowaniem w górę a rzutowaniem w dół w odniesieniu do zmiennej klasy?
Na przykład w poniższym programie klasa Animal zawiera tylko jedną metodę, ale klasa Dog zawiera dwie metody, a następnie sposób rzutowania zmiennej Dog na zmienną Animal Variable.
Jeśli rzucanie jest zakończone, to jak możemy nazwać inną metodę Dog za pomocą zmiennej Animal.
class Animal
{
public void callme()
{
System.out.println("In callme of Animal");
}
}
class Dog extends Animal
{
public void callme()
{
System.out.println("In callme of Dog");
}
public void callme2()
{
System.out.println("In callme2 of Dog");
}
}
public class UseAnimlas
{
public static void main (String [] args)
{
Dog d = new Dog();
Animal a = (Animal)d;
d.callme();
a.callme();
((Dog) a).callme2();
}
}
Dog
jestAnimal
. W większości przypadków wysyłanie w górę jest niepotrzebne, chyba że chcesz użyć określonej przeciążonej metody.callme
istnieje w obuAnimal
iDog
.callme2
istnieje tylko wDog
, który rzucasza
sięDog
, aby to działało.Odpowiedzi:
Przesyłanie w górę jest rzutowaniem do nadtypu, podczas gdy przesyłanie w dół jest rzutowaniem do podtypu. Upcasting jest zawsze dozwolony, ale downcasting wymaga sprawdzenia typu i może wyrzucić
ClassCastException
.W twoim przypadku rzut z a
Dog
do anAnimal
to upcast, ponieważ aDog
is-aAnimal
. Ogólnie rzecz biorąc, możesz upcastować, ilekroć istnieje relacja między dwiema klasami.Downcasting wyglądałby mniej więcej tak:
Zasadniczo co robisz jest mówienie kompilator, że wiesz co typu runtime obiektu naprawdę jest. Kompilator zezwoli na konwersję, ale nadal wstawi test poprawności w czasie wykonywania, aby upewnić się, że konwersja ma sens. W tym przypadku rzutowanie jest możliwe, ponieważ w czasie wykonywania
animal
jest faktycznie a,Dog
mimo że statyczny typanimal
toAnimal
.Jeśli jednak miałbyś to zrobić:
Dostałbyś
ClassCastException
. Powodem jest to, żeanimal
typ środowiska wykonawczego toAnimal
, więc kiedy powiesz środowisku wykonawczemu, aby wykonał rzutowanie, widzi, żeanimal
tak naprawdę nie jestDog
a, więc rzucaClassCastException
.Aby wywołać metodę nadklasy, możesz wykonać
super.method()
lub wykonać upcast.Aby wywołać metodę podklasy, musisz wykonać downcast. Jak pokazano powyżej,
ClassCastException
robiąc to zwykle ryzykujesz ; jednak możesz użyćinstanceof
operatora, aby sprawdzić typ środowiska uruchomieniowego obiektu przed wykonaniem rzutowania, co pozwala zapobiecClassCastException
s:źródło
ClassCastException
czy nie? Jak w pierwszym przypadku?Down-casting i up-casting wyglądał następująco:
Upcasting : Kiedy chcemy przesłać klasę Sub do klasy Super, używamy Upcasting (lub poszerzania). Dzieje się to automatycznie, nie trzeba nic robić wprost.
Downcasting : Kiedy chcemy przesłać klasę Super do klasy Sub, używamy Downcasting (lub zawężania), a Downcasting nie jest bezpośrednio możliwy w Javie, wyraźnie musimy to zrobić.
źródło
Upcasting i downcasting są ważną częścią Javy, która pozwala nam budować skomplikowane programy przy użyciu prostej składni i daje nam ogromne korzyści, takie jak polimorfizm lub grupowanie różnych obiektów. Java pozwala na traktowanie obiektu typu podklasy jako obiektu dowolnego typu nadklasy. Nazywa się to upcastingiem. Upcasting jest wykonywany automatycznie, podczas gdy downcasting musi być wykonywany ręcznie przez programistę , a ja postaram się wyjaśnić, dlaczego tak się dzieje.
Upcasting i downcasting NIE są jak rzutowanie prymitywów z jednego na drugi i uważam, że to właśnie powoduje wiele zamieszania, gdy programista zaczyna uczyć się rzucania obiektów.
Polimorfizm: wszystkie metody w Javie są domyślnie wirtualne. Oznacza to, że każda metoda może zostać zastąpiona, gdy jest używana w dziedziczeniu, chyba że ta metoda jest zadeklarowana jako ostateczna lub statyczna .
Możesz zobaczyć poniższy przykład, jak
getType();
działa w zależności od typu obiektu (Pies, Zwierzę domowe, Pies policyjny).Załóżmy, że masz trzy psy
Pies - to jest super klasa.
Pet Dog - Pet Dog przedłuża psa.
Police Dog - Police Dog przedłuża Pet Dog.
Polimorfizm: wszystkie metody w Javie są domyślnie wirtualne. Oznacza to, że każda metoda może zostać zastąpiona, gdy jest używana w dziedziczeniu, chyba że ta metoda jest zadeklarowana jako ostateczna lub statyczna. (Wyjaśnienie należy do pojęcia wirtualnych tabel).
Wydruki
Normal Dog
Wydruki
Pet Dog
Wydruki
Police Dog
Programista musi ręcznie wykonać downcasting
Podczas próby wywołania
secretID();
metody, doobj3
której istniejePoliceDog object
odniesienie, doDog
której jest superklasa w hierarchii, zgłasza błąd, ponieważobj3
nie ma dostępu dosecretId()
metody. Aby wywołać tę metodę, musisz ręcznie Downcast do tego obj3PoliceDog
który drukuje
ID
W podobny sposób, aby wywołać
dogName();
metodę wPetDog
klasie, do której musisz przejśćobj2
wPetDog
dół, ponieważ odwołuje się do obj2Dog
i nie ma dostępu dodogName();
metodyDlaczego tak się dzieje, że upcasting jest automatyczny, a downcasting musi być ręczny? Cóż, widzisz, upcasting nigdy nie zawiedzie. Ale jeśli masz grupę różnych psów i chcą spuszczonymi ich wszystkich do ich typów, to jest szansa, że niektóre z tych psów są rzeczywiście różne typy tj
PetDog
,PoliceDog
i proces nie powiedzie się, rzucającClassCastException
.To jest powód, dla którego musisz ręcznie obniżyć swoje obiekty, jeśli utworzyłeś odniesienia do obiektów do typu superklasy.
źródło
Wiem, że to pytanie zadane dość dawno temu, ale dla nowych użytkowników tego pytania. Przeczytaj ten artykuł, w którym znajduje się pełny opis upcastingu, downcastingu i korzystania z operatora instanceof
Nie ma potrzeby ręcznej aktualizacji, dzieje się to samo:
Mammal m = (Mammal)new Cat();
równaMammal m = new Cat();
Ale downcasting zawsze musi być wykonywany ręcznie:
Dlaczego tak się dzieje, że upcasting jest automatyczny, a downcasting musi być ręczny? Cóż, widzisz, upcasting nigdy nie zawiedzie. Ale jeśli masz grupę różnych zwierząt i chcesz sprowadzić je wszystkie na kota, istnieje szansa, że niektóre z tych zwierząt są w rzeczywistości psami i proces się nie powiedzie, rzucając ClassCastException. W tym miejscu należy wprowadzić przydatną funkcję o nazwie „instanceof” , która sprawdza, czy obiekt jest instancją jakiejś klasy.
Aby uzyskać więcej informacji, przeczytaj ten artykuł
źródło
Lepiej wypróbuj tę metodę upcastingu, łatwo to zrozumieć:
źródło
Może ten stół pomoże. Wywołanie
callme()
metody classParent
lub classChild
. Z zasady:źródło
1.- Nadawanie.
Wykonując upcasting, definiujesz tag pewnego typu, który wskazuje na obiekt podtypu (Typ i podtyp można nazwać klasą i podklasą, jeśli czujesz się bardziej komfortowo ...).
Co oznacza, że taki tag, animalCat, będzie miał funkcjonalność (metody) tylko typu Animal, ponieważ zadeklarowaliśmy go jako typ Animal, a nie Cat.
Możemy to robić w sposób „naturalny / niejawny / automatyczny”, w czasie kompilacji lub w czasie wykonywania, głównie dlatego, że Cat dziedziczy część swoich funkcji po Animal; na przykład move (). (A przynajmniej kot to zwierzę, prawda?)
2.- Downcasting.
Ale co by się stało, gdybyśmy musieli uzyskać funkcjonalność Cat z naszego tagu typu Animal?
Ponieważ stworzyliśmy tag animalCat wskazujący na obiekt Cat, potrzebujemy sposobu na wywołanie metod obiektu Cat z naszego tagu animalCat w sprytny, ładny sposób.
Taka procedura jest tym, co nazywamy Downcastingiem i możemy to zrobić tylko w czasie wykonywania.
Czas na kod:
źródło
Rodzic: Samochód
Dziecko: Figo
Car c1 = new Figo ();
=====
Upcasting: -
Metoda: Obiekt c1 będzie odnosił się do metod klasy (Figo - metoda musi zostać nadpisana), ponieważ klasa „Figo” jest określona jako „nowa”.
Zmienna instancji: Obiekt c1 będzie odnosił się do zmiennej instancji klasy deklaracji („samochód”).
Gdy klasa Declaration jest rodzicem i obiekt jest tworzony jako potomek, następuje rzutowanie niejawne, czyli „Upcasting”.
======
Downcasting: -
Figo f1 = (Figo) c1; //
Metoda: Obiekt f1 będzie odwoływał się do metody klasy (figo), ponieważ początkowy obiekt c1 jest tworzony z klasą „Figo”. ale po wykonaniu rzutu w dół metody, które są obecne tylko w klasie „Figo”, mogą być również odniesione przez zmienną f1.
Zmienna instancji: Obiekt f1 nie będzie odnosił się do zmiennej instancji klasy Deklaracja obiektu c1 (klasą deklaracji dla c1 jest CAR), ale przy rzutowaniu w dół będzie odnosił się do zmiennych instancji klasy Figo.
======
Użycie: Gdy obiekt jest klasy potomnej, a klasa deklaracji jest nadrzędna, a klasa podrzędna chce uzyskać dostęp do zmiennej instancji własnej klasy, a nie klasy nadrzędnej, można to zrobić za pomocą opcji „Downcasting”.
źródło
upcasting oznacza rzutowanie obiektu na nadtyp, podczas gdy downcasting oznacza rzutowanie na podtyp.
W Javie wysyłanie do góry nie jest konieczne, ponieważ jest wykonywane automatycznie. Zwykle nazywa się to rzutowaniem niejawnym. Możesz to określić, aby było jasne dla innych.
Tak więc pisząc
lub
prowadzi do dokładnie tego samego punktu iw obu przypadkach zostanie wykonany
callme()
fromDog
.Zamiast tego konieczna jest redukcja, ponieważ zdefiniowałeś
a
jako obiekt zwierzęcia. Obecnie wiesz, że jest to plikDog
, ale java nie ma gwarancji, że tak jest. Właściwie w czasie wykonywania może być inaczej i java wyrzuciClassCastException
, czy tak się stanie. Oczywiście tak nie jest w przypadku twojego przykładowego przykładu. Jeśli nie chcesz przesyłaća
doAnimal
, java nie może nawet skompilować aplikacji, ponieważAnimal
nie ma metodycallme2()
.W przykładzie nie można dotrzeć kod
callme()
zAnimal
odUseAnimlas
(boDog
go zastąpić), chyba że metoda byłaby następująca:źródło
Możemy stworzyć obiekt do Downcasting. Również w tym typie. : wywołanie metod klasy bazowej
źródło