1. Típusírás

A referenciatípusokat (osztályokat) tároló változók is különböző típusokká alakíthatók. De ez csak egyetlen típushierarchián belül működik. Nézzünk egy egyszerű példát. Tegyük fel, hogy a következő osztályhierarchiával rendelkezünk, amelyben az alábbi osztályok öröklik a fenti osztályokat.

Typecasting

A referenciatípusok, valamint a primitív típusok típusosítása szintén a szélesítő és szűkítő kategóriába sorolható.

Látjuk, hogy a macska osztály örökli a kisállat osztályt, a kisállat osztály pedig az állatok osztályát.

Ha így írunk kódot:

Animal kitten = new Cat();

Ez egy szélesítő típusú átalakítás . Implicit öntvénynek is nevezik. Kiszélesítettük a macska hivatkozást, így most egy Cat objektumra utal . Egy ilyen típusú konverzióval nem tudjuk használni a cica hivatkozást olyan metódusokhoz, amelyek a Cat osztályban jelen vannak, de az Animal osztályban hiányoznak.

A szűkülő konverzió (vagy explicit cast) az ellenkező irányban történik:

Cat cat = (Cat) kitten;

Kifejezetten jeleztük, hogy a cica változóban tárolt referenciát (amelynek típusa az Animal ) a Cat típusra szeretnénk átadni .



2. Egy objektum típusának ellenőrzése

De itt nagyon óvatosnak kell lenni. Ha ezt teszi:

Animal beast = new Cat();
Wolf grayWolf = (Wolf) beast;

A fordító engedélyezi ezt a kódot, de a program futása közben hiba lesz ! A JVM kivételt tesz:

Exception in thread "main" java.lang.ClassCastException: Cat cannot be cast to a Wolf

A Cat objektumra való hivatkozások csak olyan változókban tárolhatók, amelyek típusa a Cat osztály egyik őse: Pet, Animal vagy Object.

Miert van az?

Itt az a lényeges, hogy egy objektumhivatkozás az objektum metódusaira és változóira hivatkozik . És akkor sem lesz probléma, ha egy Animal változót használunk a Cat objektumra való hivatkozás tárolására: a Cat típusnak mindig van egy Animal típusú változója és metódusa – örökölte őket!

De ha a JVM lehetővé teszi számunkra, hogy egy Cat objektumra való hivatkozást tároljunk egy Wolf változóban, akkor előfordulhat, hogy megpróbáljuk a grayWolf változót használni egy olyan metódus meghívására, amely nem létezik az abban a változóban tárolt Cat objektumban. . Ezért ez az elrendezés nem megengedett.

A Java speciális instanceofoperátorral rendelkezik, amely lehetővé teszi annak ellenőrzését, hogy egy objektum egy bizonyos típusú-e, és ezért tárolható-e egy bizonyos típusú változóban. Elég egyszerűnek tűnik:

variable instanceof Type

Példa:

Animal beast = new Cat();
if (beast instanceof Wolf)
{
   Wolf grayWolf = (Wolf) beast;
}

Ez a kód nem okoz hibát – még futás közben sem.

Íme néhány további példa, amelyek illusztrálják a helyzetet:

Szélesítő típus átalakítás Leírás
Cow cow = new Whale();

Ez egy klasszikus szélesítő konverzió – nincs szükség típuskonverziós operátorra. Most már csak az osztályban definiált metódusok Cowhívhatók meg az objektumon Whale.

A cowváltozón a fordító csak azokat a metódusokat engedi meghívni, amelyek típusa (az Cowosztály) rendelkezik.

Szűkítő típus átalakítás
Cow cow = new Whale();
if (cow instanceof Whale)
{
   Whale whale = (Whale) cow;
}
Klasszikus szűkítő konverzió: Hozzá kell adni egy típusellenőrzést és egy cast operátort.
A Cow cowváltozó egy objektumra való hivatkozást tárol Whale.
Ellenőrizzük, hogy ez a helyzet , majd végrehajtjuk a (szűkítő) típuskonverziót. Vagy ahogy más néven:
egy típusú öntvény
.

Cow cow = new Cow();
Whale whale = (Whale) cow; // Exception
Szűkíthet egy referenciatípust az objektum típusának ellenőrzése nélkül.
Ha a cowváltozó olyan objektumra hivatkozik, amely nem a Whale, akkor a InvalidClassCastExceptiongenerálódik.


3. Az eredeti metódus meghívása: a superkulcsszó

Amikor felülírjuk egy szülő osztály metódusát, néha ahelyett, hogy a sajátunkkal cserélnénk le, csak kicsit szeretnénk kiegészíteni.

Jó lenne, ha a szülő osztály metódusát be tudnánk használni a metódusunkban, majd végrehajtanánk a saját kódunk egy részét. Vagy talán először futtassuk le a saját kódunkat, majd hívjuk meg a szülő osztály metódusát.

A Java pedig éppen ezt teszi lehetővé. A szülőosztály metódusának meghívásához tegye a következőket:

super.method(arguments);

Példák:

class PeaceTime
{
   public double getPi()
   {
      return 3.14;
   }
}

class WarTime extends PeaceTime
{
   public double getPi()
   {
      return super.getPi()*2;  // 3.14*2
   }
}

Háborús időben a Pi6 értéke nagyobb lehet! Természetesen viccelünk, de ez a példa bemutatja, hogyan működik mindez.

Íme még néhány példa, hogy kicsit tisztázzuk a dolgokat:

Kód Leírás
class Cow
{
   public void printAll()
   {
      printColor();
      printName();
   }

   public void printColor()
   {
      System.out.println("I'm a white whale");
   }

   public void printName()
   {
      System.out.println("I'm a cow");
   }
}

class Whale extends Cow
{
   public void printName()
   {
      System.out.print("This is incorrect: ");
      super.printName();
      System.out.println("I'm a whale");
   }
}
Cowés Whaleosztályok
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printAll();
}
A képernyő kimenete a következő lesz:
I'm a white whale
This is incorrect: I'm a cow
I'm a whale

Ez kemény dolog. Őszintén szólva, ez az egyik legnehezebb dolog az OOP -ban . Ennek ellenére tudnia kell és meg kell értenie.