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.
public class Dog{
public String getType () {
System.out.println("NormalDog");
return "NormalDog";
}
}
/**
* Pet Dog has an extra method dogName()
*/
public class PetDog extends Dog{
public String getType () {
System.out.println("PetDog");
return "PetDog";
}
public String dogName () {
System.out.println("I don't have Name !!");
return "NO Name";
}
}
/**
* Police Dog has an extra method secretId()
*/
public class PoliceDog extends PetDog{
public String secretId() {
System.out.println("ID");
return "ID";
}
public String getType () {
System.out.println("I am a Police Dog");
return "Police 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).
Virtual Table / Dispatch Table: Tabela wysyłkowa obiektu będzie zawierać adresy dynamicznie powiązanych metod obiektu. Wywołania metod są wykonywane przez pobranie adresu metody z tabeli wysyłkowej obiektu. Tablica wysyłki jest taka sama dla wszystkich obiektów należących do tej samej klasy i dlatego jest zwykle między nimi współdzielona.
public static void main (String[] args) {
/**
* Creating the different objects with super class Reference
*/
Dog obj1 = new Dog();
` /**
* Object of Pet Dog is created with Dog Reference since
* Upcasting is done automatically for us we don't have to worry about it
*
*/
Dog obj2 = new PetDog();
` /**
* Object of Police Dog is created with Dog Reference since
* Upcasting is done automatically for us we don't have to worry
* about it here even though we are extending PoliceDog with PetDog
* since PetDog is extending Dog Java automatically upcast for us
*/
Dog obj3 = new PoliceDog();
}
obj1.getType();
Wydruki Normal Dog
obj2.getType();
Wydruki Pet Dog
obj3.getType();
Wydruki Police Dog
Programista musi ręcznie wykonać downcasting
Podczas próby wywołania secretID();
metody, do obj3
której istnieje PoliceDog object
odniesienie, do Dog
której jest superklasa w hierarchii, zgłasza błąd, ponieważ obj3
nie ma dostępu do secretId()
metody. Aby wywołać tę metodę, musisz ręcznie Downcast do tego obj3 PoliceDog
( (PoliceDog)obj3).secretID();
który drukuje ID
W podobny sposób, aby wywołać dogName();
metodę w PetDog
klasie, do której musisz przejść obj2
w PetDog
dół, ponieważ odwołuje się do obj2 Dog
i nie ma dostępu do dogName();
metody
( (PetDog)obj2).dogName();
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 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ąc ClassCastException
.
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.
Uwaga: tutaj przez odniesienie oznacza, że nie zmieniasz adresu pamięci swoich ojectów, gdy je przesyłasz w dół, nadal pozostaje taki sam, w tym przypadku po prostu grupujesz je według określonego typu Dog
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.