Object Type Casting Java-ban

1. Áttekintés

A Java típusú rendszer kétféle típusból áll: primitívek és hivatkozások.

Ebben a cikkben a primitív konverziókat ismertettük, és az itt szereplő referenciákra fogunk összpontosítani, hogy jól megértsük, hogyan kezeli a Java a típusokat.

2. Primitiv vs. Referencia

Bár a primitív konverziók és a referencia-változó leadása hasonlónak tűnhet, meglehetősen eltérő fogalmak.

Mindkét esetben „átalakítjuk” az egyik típust a másikba. De egyszerűsítve a primitív változó tartalmazza az értékét, a primitív változó átalakítása pedig visszafordíthatatlan változásokat jelent az értékében:

dupla myDouble = 1,1; int myInt = (int) myDouble; assertNotEquals (myDouble, myInt);

A fenti példában szereplő átalakítás után myInt változó az 1, és nem tudjuk visszaállítani az előző értéket 1.1 ebből.

A referencia változók különböznek; a referencia változó csak egy objektumra vonatkozik, de nem tartalmazza magát az objektumot.

A referenciaváltozó leadása pedig nem érinti az objektumot, amelyre hivatkozik, hanem csak más módon címkézi meg ezt az objektumot, kibővítve vagy szűkítve a vele való együttműködés lehetőségeit. Az upcasting szűkíti az objektum számára elérhető módszerek és tulajdonságok listáját, és a downcasting kiterjesztheti azt.

A hivatkozás olyan, mint egy objektum távirányítója. A távvezérlőnek típusától függően több vagy kevesebb gombja van, és maga az objektum is egy halomban van tárolva. Az öntés során megváltoztatjuk a távirányító típusát, de magát az objektumot nem.

3. Felborulás

Az alosztályról a szuperosztályra való öntést nevezzük upcastingnak. Általában a feltöltést implicit módon a fordító végzi.

Az upcasting szorosan összefügg az örökléssel - a Java másik alapkoncepciójával. Gyakori a referenciaváltozók használata egy konkrétabb típusra való hivatkozáshoz. És minden alkalommal, amikor ezt megtesszük, implicit felvetés történik.

Az elárasztás bemutatásához definiáljunk egy Állat osztály:

állatosztály állat {public void eat () {// ...}}

Most terjesszük ki Állat:

public class Cat meghosszabbítja az állatot {public void eat () {// ...} public void meow () {// ...}}

Most létrehozhatunk egy objektumot Macska osztály és rendelje hozzá a típus referencia változójához Macska:

Macskamacska = új Macska ();

És hozzárendelhetjük a típus referenciaváltozójához is Állat:

Állati állat = macska;

A fenti feladatban implicit feltárás történik. Megtehetnénk kifejezetten:

állat = (állat) macska;

De nem kell kifejezetten felvetni az öröklési fát. A fordító ezt tudja macska egy Állat és nem jelenít meg hibákat.

Megjegyzés: ez a hivatkozás a deklarált típus bármely altípusára vonatkozhat.

Az upcasting használatával korlátoztuk a rendelkezésre álló módszerek számát Macska de nem változtatta meg magát a példányt. Most nem tehetünk semmit, ami specifikus Macska - nem hivatkozhatunk miaú() a állat változó.

Habár Macska tárgy marad Macska objektum, hívás miaú() fordító hibát okozna:

// animal.meow (); A meow () módszer nincs meghatározva az Animal típusnál

Felhívni miaú() le kell eresztenünk állat, és ezt később megtesszük.

De most leírjuk, mi adja a felzárkózást. Az upcastingnak köszönhetően kihasználhatjuk a polimorfizmus előnyeit.

3.1. Polimorfizmus

Határozzunk meg egy másik alosztályt Állat, a Kutya osztály:

public class Kutya kiterjeszti az állatot {public void eat () {// ...}}

Most meghatározhatjuk a hírcsatorna () módszer, amely minden macskát és kutyát szeret állatok:

public class AnimalFeeder {public void feed (Állatok felsorolása) {animals.forEach (animal -> {animal.eat ();}); }}

Nem akarjuk AnimalFeeder hogy melyik érdekli állat szerepel a listán - a Macska vagy a Kutya. Ban,-ben hírcsatorna () módszer mind állatok.

Az implicit felvetés akkor következik be, amikor egy adott típusú objektumot hozzáadunk a állatok lista:

Állatok felsorolása = new ArrayList (); állatok.add (új Macska ()); állatok.add (új Kutya ()); új AnimalFeeder (). takarmány (állatok);

Hozzáadunk macskákat és kutyákat, amelyek fel vannak borulva Állat típus implicit módon. Minden egyes Macska egy Állat és mindegyik Kutya egy Állat. Polimorfak.

Egyébként az összes Java objektum polimorf, mert minden objektum egy Tárgy legalább. Rendelhetünk egy példányt Állat a referencia változóra Tárgy típus és a fordító nem panaszkodik:

Objektum objektum = new Animal ();

Ezért az összes általunk létrehozott Java objektum már rendelkezik Tárgy specifikus módszerek, például toString ().

Ugyancsak gyakori az interfészre történő frissítés.

Alkothatunk Elzár interfész és gyártmány Macska hajtsa végre:

nyilvános felület Mew {public void meow (); } public class Cat meghosszabbítja az állatokat Mew {public void eat () {// ...} public void meow () {// ...}}

Most bármelyik Macska objektum is felborítható Elzár:

Mew mew = új Macska ();

Macska egy Elzár, a feltárás legális és implicit módon történik.

Így, Macska egy Elzár, Állat, Tárgy, és Macska. A példánkban mind a négy típus referenciaváltozóihoz rendelhető.

3.2. Felülbíráló

A fenti példában a eszik() módszert felülírják. Ez azt jelenti, hogy bár eszik() változójára hívjuk meg Állat típusú, a munkát valós tárgyakra - macskákra és kutyákra - hivatkozott módszerekkel végzik:

public void feed (Sorolja fel az állatokat) {animals.forEach (animal -> {animal.eat ();}); }

Ha felveszünk néhány naplózást az osztályainkba, akkor meglátjuk Macska’S és KutyaMódszereit nevezzük:

web - 2018-02-15 22: 48: 49,354 [main] INFO com.baeldung.casting.Cat - macska eszik webet - 2018-02-15 22: 48: 49,363 [main] INFO com.baeldung.casting.Dog - a kutya eszik 

Összefoglalva:

  • A referencia változó akkor hivatkozhat objektumra, ha az objektum ugyanolyan típusú, mint egy változó, vagy ha altípus
  • A feltárás implicit módon történik
  • Minden Java objektum polimorf, és a felcsapódás miatt szupertipus objektumként kezelhető

4. Lecsökkentés

Mi van, ha a típusú változót akarjuk használni Állat csak a számára elérhető módszer meghívására Macska osztály? Itt jön a lebukás. Ez a szuperosztályból az alosztályba történő casting.

Vegyünk egy példát:

Állati állat = új Macska ();

Tudjuk állat változó a Macska. És szeretnénk hivatkozni Macska’S miaú() módszer a állat. De a fordító ezt panaszolja miaú() módszer nem létezik a típushoz Állat.

Hívni miaú() le kellene borítanunk állat nak nek Macska:

((Macska) állat) .maow ();

A belső zárójeleket és az azokban szereplő típust néha cast operátornak nevezik. Ne feledje, hogy a kód fordításához külső zárójelekre is szükség van.

Írjuk át az előzőt AnimalFeeder példa azzal miaú() módszer:

public class AnimalFeeder {public void feed (Állatok felsorolása) {animals.forEach (animal -> {animal.eat (); if (Macska állati példánya) {((Cat) állat) .meow ();}}); }}

Most hozzáférünk az összes rendelkezésre álló módszerhez Macska osztály. Nézze meg a naplót, hogy megbizonyosodjon arról miaú() valójában:

web - 2018-02-16 18: 13: 45,445 [main] INFO com.baeldung.casting.Cat - macska eszik webet - 2018-02-16 18: 13: 45,454 [main] INFO com.baeldung.casting.Cat - meow web - 2018-02-16 18: 13: 45,455 [main] INFO com.baeldung.casting.Dog - kutya eszik

Ne feledje, hogy a fenti példában csak azokat az objektumokat próbáljuk lebecsülni, amelyek valóban példányai Macska. Ehhez az operátort használjuk Például az.

4.1. Például az Operátor

Gyakran használjuk Például az operátor lefelé állítás előtt, hogy ellenőrizze, hogy az objektum az adott típushoz tartozik-e:

if (Macska állat példánya) {((Macska) állat) .meow (); }

4.2. ClassCastException

Ha nem ellenőriztük volna a típust a Például az operátor, a fordító nem panaszkodott volna. De futás közben lenne kivétel.

Ennek bemutatásához távolítsuk el a Például az operátor a fenti kódból:

public void uncheckedFeed (Állatok felsorolása) {animals.forEach (animal -> {animal.eat (); ((Cat) animal) .meow ();}); }

Ez a kód problémák nélkül áll össze. De ha megpróbáljuk futtatni, akkor kivételt fogunk látni:

java.lang.ClassCastException: com.baeldung.casting.Dog nem lehet rávetni com.baeldung.casting.Cat

Ez azt jelenti, hogy megpróbálunk átalakítani egy objektumot, amelynek egy példánya Kutya ba be Macska példa.

ClassCastException 'Mindig futásidőben dobjuk, ha az a típus, amelyre lesüllyesztjük, nem egyezik a valós objektum típusával.

Ne feledje, hogy ha megpróbálunk le nem váltani egy nem kapcsolódó típust, akkor a fordító ezt nem engedélyezi:

Állati állat; Húr s = (Húr) állat;

A fordító azt mondja: „Nem lehet állatról sztringre leadni”.

A kód összeállításához mindkét típusnak ugyanabban az öröklési fában kell lennie.

Összegezzük:

  • Downcasting szükséges ahhoz, hogy hozzáférhessünk az alosztályhoz tartozó tagokhoz
  • A lekicsinylés cast operátorral történik
  • Egy objektum biztonságos lebukásához szükségünk van Például az operátor
  • Ha a valós objektum nem egyezik meg azzal a típussal, amelyre lefelé állítottunk, akkor ClassCastException futás közben dobják

5. öntvény() Módszer

Van egy másik módszer az objektumok öntésére a módszerekkel Osztály:

public void whenDowncastToCatWithCastMethod_thenMeowIsCalled () {Animal animal = new Cat (); if (Cat.class.isInstance (állat)) {Cat cat = Cat.class.cast (állat); cat.meow (); }}

A fenti példában öntvény() és isInstance () módszereket használnak öntött és Például az üzemeltetőknek megfelelően.

Gyakori a használata öntvény() és isInstance () módszerek általános típusokkal.

Alkossunk AnimalFeederGeneric osztályban hírcsatorna () módszer, amely a típusparaméter értékétől függően csak egyetlen állatfajtát - macskát vagy kutyát „etet”:

public class AnimalFeederGeneric {private Class type; public AnimalFeederGeneric (Osztálytípus) {this.type = type; } public List feed (List állatok) {List list = new ArrayList (); animals.forEach (animal -> {if (type.isInstance (animal)) {T objAsType = type.cast (animal); list.add (objAsType);}}); visszatérési lista; }}

A hírcsatorna () A módszer minden állatot ellenőriz, és csak azokat adja vissza, amelyek T.

Ne feledje, hogy a Osztály a példányt is át kell adni az általános osztálynak, mivel nem tudjuk megkapni a type paraméterből T. Példánkban a konstruktorban adjuk át.

Csináljuk T egyenlő Macska és győződjön meg arról, hogy a módszer csak macskákat eredményez:

@Test public void whenParameterCat_thenOnlyCatsFed () {Állatok felsorolása = new ArrayList (); állatok.add (új Macska ()); állatok.add (új Kutya ()); AnimalFeederGeneric catFeeder = új AnimalFeederGeneric (Kat. Osztály); List feded Animals = catFeeder.feed (állatok); assertTrue (fedAnimals.size () == 1); assertTrue (fedAnimals.get (0) Cat példánya); }

6. Következtetés

Ebben az alap oktatóanyagban megvizsgáltuk, hogy mi a felpörgetés, leszámolás, hogyan kell használni őket, és ezek a fogalmak hogyan segíthetnek a polimorfizmus előnyeinek kihasználásában.

Mint mindig, a cikk kódja is elérhető a GitHubon.