1. Tipare

Variabilele care stochează tipuri de referință (clase) pot fi, de asemenea, convertite în diferite tipuri. Dar acest lucru funcționează doar într-o singură ierarhie de tip. Să ne uităm la un exemplu simplu. Să presupunem că avem următoarea ierarhie a claselor, în care clasele de mai jos moștenesc clasele de mai sus.

Tipare

Tipărirea tipurilor de referință, precum și a celor primitive este, de asemenea, clasificată ca lărgire și îngustare.

Vedem că clasa Cat moștenește clasa Pet, iar clasa Pet, la rândul său, moștenește clasa Animal.

Dacă scriem cod astfel:

Animal kitten = new Cat();

This is a widening type conversion. It is also called an implicit cast. We've widened the cat reference so that it now refers to a Cat object. With a type conversion like this, we will not be able to use the kitten reference to call methods that are present in the Cat class but absent in the Animal class.

A narrowing conversion (or explicit cast) happens in the opposite direction:

Cat cat = (Cat) kitten;

We explicitly indicated that we want to cast the reference stored in the kitten variable (whose type is Animal) to the Cat type.



2. Checking the type of an object

But you need to be very careful here. If you do this:

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

Compilatorul va permite acest cod, dar va apărea o eroare când programul va rula! JVM-ul va lansa o excepție:

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

Referințele la un obiect Cat pot fi stocate numai în variabile al căror tip este un strămoș al clasei Cat: Animal de companie, Animal sau Obiect.

De ce este asta?

Punctul relevant aici este că o referință la obiect este folosită pentru a se referi la metodele și variabilele acelui obiect . Și nu vor fi probleme dacă folosim o variabilă Animal pentru a stoca o referință la un obiect Cat: tipul Cat are întotdeauna variabile și metode de tip Animal - le-a moștenit!

But if the JVM allowed us to store a reference to a Cat object in a Wolf variable, then we might have a situation where we might try to use the grayWolf variable to call a method that does not exist in the Cat object stored in that variable. That's why this arrangement is not allowed.

Java has a special instanceof operator that lets you check if an object is of a certain type and therefore can be stored into a variable of a certain type. It looks quite simple:

variable instanceof Type

Example:

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

This code won't cause errors — even at runtime.

Here are some more examples that illustrate the situation:

Widening type conversion Description
Cow cow = new Whale();

Aceasta este o conversie clasică de lărgire — nu este necesar niciun operator de conversie de tip. Acum doar metodele definite în Cowclasă pot fi apelate pe Whaleobiect.

Pe cowvariabila , compilatorul vă va permite să apelați numai metodele pe care le Coware tipul său (clasa).

Conversie tip îngustare
Cow cow = new Whale();
if (cow instanceof Whale)
{
   Whale whale = (Whale) cow;
}
Conversie clasică de îngustare: trebuie să adăugați o verificare de tip și un operator de distribuție.
Variabila Cow cowstochează o referință la un Whaleobiect.
Verificăm că acesta este cazul și apoi efectuăm o conversie de tip (îngustare). Sau cum se mai spune:
un tip turnat
.

Cow cow = new Cow();
Whale whale = (Whale) cow; // Exception
Puteți restrânge un tip de referință fără a verifica tipul obiectului.
Dacă cowvariabila se referă la un obiect care nu este un Whale, atunci InvalidClassCastExceptionva fi generat un.


3. Apelarea metodei originale: supercuvântul cheie

Când trecem peste metoda unei clase părinte, uneori, în loc să o înlocuim cu propria noastră, vrem doar să o completăm puțin.

Ar fi grozav dacă am putea folosi metoda clasei părinte în metoda noastră și apoi să executăm o parte din propriul nostru cod. Sau poate executam mai întâi propriul nostru cod și apoi apelăm metoda clasei părinte.

Și Java ne permite tocmai asta. Pentru a apela o metodă a clasei părinte, procedați astfel:

super.method(arguments);

Exemple:

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

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

În timp de război, valoarea lui Pipoate fi mai mare de 6! Desigur, glumim, dar acest exemplu demonstrează cum pot funcționa toate acestea.

Iată încă câteva exemple pentru a clarifica puțin lucrurile:

Cod Descriere
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");
   }
}
Cowsi Whaleclase
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printAll();
}
Ieșirea ecranului va fi:
I'm a white whale
This is incorrect: I'm a cow
I'm a whale

Acestea sunt lucruri grele. Sincer, este unul dintre cele mai dificile lucruri în POO . Acestea fiind spuse, trebuie să știți și să înțelegeți.