Szia! Egy korábbi leckében a primitív típusok öntését tárgyaltuk. Emlékezzünk vissza röviden a megbeszéltekre.
A primitív típusokat (jelen esetben numerikus típusokat) fészkelő babákként képzeltük el, amelyek mérete az elfoglalt memória mennyiségétől függően változik. Emlékezni fog, hogy egy kisebb babát egy nagyobbba tenni egyszerű a való életben és a Java programozásban is.
Vegyünk egy másik érdekesebb példát:

public class Main {
public static void main(String[] args) {
int bigNumber = 10000000;
short smallNumber = (short) bigNumber;
System.out.println(smallNumber);
}
}
Ez egy példa az automatikus átalakításra vagy szélesítésre . Ez magától történik, így nem kell további kódot írnia. Végül nem csinálunk semmi szokatlant: csak egy kisebb babát teszünk egy nagyobb babába. Más kérdés, ha megpróbáljuk az ellenkezőjét tenni, és egy nagyobb orosz babát teszünk egy kisebb babába. A való életben ezt nem tudod megtenni, de a programozásban igen. De van egy árnyalat. Ha megpróbálunk int
egy short
változót betenni, akkor a dolgok nem mennek olyan simán. Végül is a short
változó csak 16 bit információt tartalmaz, de egy int
32 bitet foglal el! Ennek eredményeként az átadott érték torzul. A fordító hibaüzenetet ad nekünk (' Haver, valami gyanúsat csinálsz!'). De ha kifejezetten megjelöljük azt a típust, amelyre átváltjuk az értéket, akkor az elindul és végrehajtja a műveletet.
public class Main {
public static void main(String[] args) {
int bigNumber = 10000000;
bigNumber = (short) bigNumber;
System.out.println(bigNumber);
}
}
Pontosan ezt tettük a fenti példában. A művelet megtörtént, de mivel a változó csak 16-ot tud befogadni a 32 bájtból, a végső érték torzul, és a -27008short
számot kapjuk . Az ilyen műveletet explicit konverziónak vagy szűkítésnek nevezik .
Példák a referenciatípusok szélesítésére és szűkítésére
Most beszéljünk ugyanazokról az operátorokról, amelyek nem primitív típusokra vonatkoznak, hanem objektumokra és referenciaváltozókra ! Hogyan működik ez Java-ban? Valójában nagyon egyszerű. Vannak olyan tárgyak, amelyek nem kapcsolódnak egymáshoz. Logikus lenne azt feltételezni, hogy nem konvertálhatók egymásba, sem kifejezetten, sem automatikusan:
public class Cat {
}
public class Dog {
}
public class Main {
public static void main(String[] args) {
Cat cat = new Dog(); // Error!
}
}
Itt természetesen hibát kapunk. A Cat
és Dog
osztályok nem kapcsolódnak egymáshoz, és nem írtunk „átalakítót”, amely egyikből a másikba léphet. Logikus, hogy ezt nem tehetjük meg: a fordítónak fogalma sincs, hogyan konvertálja ezeket az objektumokat egyik típusból a másikba. Ha a tárgyak összefüggenek, az már más kérdés! Hogyan kapcsolódik? Mindenekelőtt az öröklés útján. Próbáljuk meg az öröklődés használatával létrehozni egy kis osztályrendszert. Lesz egy közös osztályunk az állatok képviseletére:
public class Animal {
public void introduce() {
System.out.println("I'm Animal");
}
}
Mindenki tudja, hogy az állatok háziasítottak (háziállatok) vagy vadon is lehetnek:
public class WildAnimal extends Animal {
public void introduce() {
System.out.println("I'm WildAnimal");
}
}
public class Pet extends Animal {
public void introduce() {
System.out.println("I'm Pet");
}
}
Vegyük például a szemfogakat – vannak házi kutyáink és prérifarkasaink:
public class Dog extends Pet {
public void introduce() {
System.out.println("I'm Dog");
}
}
public class Coyote extends WildAnimal {
public void introduce() {
System.out.println ("I'm Coyote");
}
}
Kifejezetten a legalapvetőbb osztályokat választottuk ki, hogy könnyebben érthetőek legyenek. Valójában nincs szükségünk mezőkre, és egy módszer is elég. Próbáljuk meg végrehajtani ezt a kódot:
public class Main {
public static void main(String[] args) {
Animal animal = new Pet();
animal.introduce();
}
}
Szerinted mi fog megjelenni a konzolon? introduce
Az osztály metódusa Pet
vagy az osztály lesz Animal
meghívva? Mielőtt folytatná az olvasást, próbálja meg indokolni a választ. És itt az eredmény! Kisállat vagyok Miért kaptuk? Minden egyszerű. Van egy szülőváltozónk és egy leszármazott objektumunk. Írással,
Animal animal = new Pet();
kiszélesítettünk egy Pet
hivatkozást és hozzárendeltük egy változóhoz Animal
. A primitív típusokhoz hasonlóan a referenciatípusok automatikusan kibővülnek a Java-ban. Ehhez nem kell további kódot írnia. Most egy leszármazott objektum van hozzárendelve egy szülőhivatkozáshoz. Ennek eredményeként azt látjuk, hogy a metódushívás a leszármazott osztályon történik. Ha még mindig nem érti teljesen, miért működik ez a kód, írja át egyszerű nyelven:
Animal animal = new DomesticatedAnimal();
Nincs ezzel semmi gond, igaz? Képzelje el, hogy ez a való élet, és a hivatkozás egyszerűen egy papírcímke, amelyen az „Állat” felirat szerepel. Ha elveszi azt a papírdarabot, és rögzíti bármely háziállat nyakörvéhez, minden rendben lesz. Hiszen minden házi kedvenc állat! A fordított folyamat – az öröklési fán a leszármazottak felé haladva – szűkül:
public class Main {
public static void main(String[] args) {
WildAnimal wildAnimal = new Coyote();
Coyote coyote = (Coyote) wildAnimal;
coyote.introduce();
}
}
Mint látható, itt egyértelműen jelezzük azt az osztályt, amelyre az objektumunkat konvertálni szeretnénk. Korábban volt egy WildAnimal
változónk, most pedig egy Coyote
, ami alacsonyabb az öröklődési fán. Érthető, hogy kifejezett jelzés nélkül a fordító nem enged ilyen műveletet, de ha zárójelben megadjuk a típust, akkor minden működik. 
public class Main {
public static void main(String[] args) {
Pet pet = new Animal(); // Error!
}
}
A fordító hibát generál! De miért? Mert szülőobjektumot próbál hozzárendelni egy leszármazott hivatkozáshoz. Más szavakkal, valami ilyesmit próbál tenni:
DomesticatedAnimal domesticatedAnimal = new Animal();
Nos, talán minden működni fog, ha kifejezetten megadjuk a típust, amelyre konvertálni próbálunk? Ez működött a számokkal – tegyünk egy próbát! :)
public class Main {
public static void main(String[] args) {
Pet pet = (Pet) new Animal();
}
}
Kivétel a "main" szálban java.lang.ClassCastException: Az állat nem küldhető Pet Error-ba! A fordító ezúttal nem kiabált velünk, de végül kivétellel végeztünk. Az okot már tudjuk: szülőobjektumot próbálunk hozzárendelni egy leszármazott hivatkozáshoz. De pontosan miért nem teheti meg? Mert nem minden állat háziasított állat. Létrehozott egy Animal
objektumot, és megpróbálja hozzárendelni egy változóhoz Pet
. A prérifarkas is egy Animal
, de nem az Pet
. Más szóval, amikor írsz
Pet pet = (Pet) new Animal();
new Animal()
bármilyen állatot képviselhet, nem feltétlenül háziállatot! Természetesen a Pet pet
változó csak házi kedvencek (és leszármazottjaik) tárolására alkalmas, bármilyen típusú állat tárolására nem. Ezért ClassCastException
jött létre egy speciális Java-kivétel, az olyan esetekre, amikor az osztályok átküldése közben hiba történik. Nézzük át újra, hogy világosabb legyen a helyzet. A szülőhivatkozás egy leszármazott osztály példányaira mutathat:
public class Main {
public static void main(String[] args) {
Pet pet = new Pet();
Animal animal = pet;
Pet pet2 = (Pet) animal;
pet2.introduce();
}
}
Nálunk például nincs gond. Van egy Pet
objektumunk, amelyre egy változó hivatkozik Pet
. Később egy Animal
hivatkozás ugyanerre az objektumra mutatott. Ezt követően konvertálunk animal
egy Pet
. Egyébként miért működött ez nálunk? Múltkor kivételt kaptunk! Mert ezúttal eredeti tárgyunk egy Pet
!
Pet pet = new Pet();
De az utolsó példában ez egy Animal
objektum volt:
Pet pet = (Pet) new Animal();
Nem rendelhet ősobjektumot egy leszármazott változóhoz. Megteheti az ellenkezőjét.
További olvasnivalók: |
---|
GO TO FULL VERSION