CodeGym /Java blog /Véletlen /Referenciatípusok szélesítése, szűkítése
John Squirrels
Szint
San Francisco

Referenciatípusok szélesítése, szűkítése

Megjelent a csoportban
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. Referenciatípusok szélesítése és szűkítése - 1A 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.

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 integy shortváltozót betenni, akkor a dolgok nem mennek olyan simán. Végül is a shortváltozó csak 16 bit információt tartalmaz, de egy int32 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 Dogosztá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? introduceAz osztály metódusa Petvagy az osztály lesz Animalmeghí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 Pethivatkozá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 WildAnimalvá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. Referenciatípusok szélesítése és szűkítése - 2Vegyünk egy másik érdekesebb példát:

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 Animalobjektumot, é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 petvá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 ClassCastExceptionjö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 Petobjektumunk, amelyre egy változó hivatkozik Pet. Később egy Animalhivatkozás ugyanerre az objektumra mutatott. Ezt követően konvertálunk animalegy 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 Animalobjektum volt:

Pet pet = (Pet) new Animal();
Nem rendelhet ősobjektumot egy leszármazott változóhoz. Megteheti az ellenkezőjét.
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION