1. Typisierung

Variablen, die Referenztypen (Klassen) speichern, können auch in andere Typen konvertiert werden. Dies funktioniert jedoch nur innerhalb einer einzelnen Typhierarchie. Schauen wir uns ein einfaches Beispiel an. Angenommen, wir haben die folgende Klassenhierarchie, in der die Klassen unten die Klassen oben erben.

Typisierung

Die Typumwandlung sowohl von Referenztypen als auch von primitiven Typen wird ebenfalls als Verbreiterung und Verengung kategorisiert.

Wir sehen, dass die Cat-Klasse die Pet-Klasse erbt und die Pet-Klasse wiederum die Animal-Klasse.

Wenn wir Code wie diesen schreiben:

Animal kitten = new Cat();

Dies ist eine erweiternde Typkonvertierung . Man spricht auch von einer impliziten Besetzung. Wir haben die Cat- Referenz erweitert, sodass sie sich nun auf ein Cat- Objekt bezieht. Bei einer solchen Typkonvertierung können wir die Kitten- Referenz nicht zum Aufrufen von Methoden verwenden, die in der Cat- Klasse vorhanden, aber in der Animal- Klasse nicht vorhanden sind.

Eine einschränkende Konvertierung (oder explizite Umwandlung) erfolgt in die entgegengesetzte Richtung:

Cat cat = (Cat) kitten;

Wir haben ausdrücklich darauf hingewiesen, dass wir die in der Kitten- Variable (deren Typ Animal ist ) gespeicherte Referenz in den Cat- Typ umwandeln möchten .



2. Überprüfen des Typs eines Objekts

Aber hier muss man sehr vorsichtig sein. Wenn du das tust:

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

Der Compiler lässt diesen Code zu, aber beim Ausführen des Programms tritt ein Fehler auf ! Die JVM löst eine Ausnahme aus:

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

Verweise auf ein Cat- Objekt können nur in Variablen gespeichert werden, deren Typ ein Vorfahre der Cat-Klasse ist: Pet, Animal oder Object.

Warum das?

Der relevante Punkt hierbei ist, dass eine Objektreferenz verwendet wird, um auf die Methoden und Variablen dieses Objekts zu verweisen . Und es wird keine Probleme geben, wenn wir eine Animal-Variable verwenden, um einen Verweis auf ein Cat-Objekt zu speichern: Der Cat-Typ hat immer Variablen und Methoden vom Animal-Typ – er hat sie geerbt!

Aber wenn die JVM es uns erlauben würde, einen Verweis auf ein Cat-Objekt in einer Wolf-Variablen zu speichern, dann könnten wir in eine Situation kommen, in der wir versuchen könnten, die Variable greyWolf zu verwenden , um eine Methode aufzurufen, die in dem in dieser Variablen gespeicherten Cat-Objekt nicht existiert . Deshalb ist diese Anordnung nicht zulässig.

Java verfügt über einen speziellen instanceofOperator, mit dem Sie prüfen können, ob ein Objekt von einem bestimmten Typ ist und daher in einer Variablen eines bestimmten Typs gespeichert werden kann. Es sieht ganz einfach aus:

variable instanceof Type

Beispiel:

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

Dieser Code verursacht keine Fehler – auch nicht zur Laufzeit.

Hier sind einige weitere Beispiele, die die Situation veranschaulichen:

Erweiterungstypkonvertierung Beschreibung
Cow cow = new Whale();

Dies ist eine klassische Erweiterungskonvertierung – es ist kein Typkonvertierungsoperator erforderlich. Jetzt können nur noch die in der Klasse definierten Methoden Cowfür das Objekt aufgerufen werden Whale.

Für die cowVariable lässt der Compiler Sie nur Methoden aufrufen, die ihr Typ (die CowKlasse) hat.

Einschränkende Typkonvertierung
Cow cow = new Whale();
if (cow instanceof Whale)
{
   Whale whale = (Whale) cow;
}
Klassische einschränkende Konvertierung: Sie müssen eine Typprüfung und einen Umwandlungsoperator hinzufügen.
Die Cow cowVariable speichert einen Verweis auf ein WhaleObjekt.
Wir überprüfen, ob dies der Fall ist , und führen dann eine (einschränkende) Typkonvertierung durch. Oder wie es auch heißt:
eine Typumwandlung
.

Cow cow = new Cow();
Whale whale = (Whale) cow; // Exception
Sie können einen Referenztyp eingrenzen, ohne den Typ des Objekts zu überprüfen.
Wenn sich die cowVariable auf ein Objekt bezieht, das kein ist , wird Whaleein generiert.InvalidClassCastException


3. Aufruf der ursprünglichen Methode: das superSchlüsselwort

Wenn wir die Methode einer übergeordneten Klasse überschreiben, möchten wir sie manchmal nur geringfügig ergänzen, anstatt sie durch unsere eigene zu ersetzen.

Es wäre cool, wenn wir die Methode der übergeordneten Klasse in unsere Methode integrieren und dann einen Teil unseres eigenen Codes ausführen könnten. Oder führen Sie vielleicht zuerst unseren eigenen Code aus und rufen Sie dann die Methode der übergeordneten Klasse auf.

Und Java ermöglicht uns genau das. Gehen Sie wie folgt vor, um eine Methode der übergeordneten Klasse aufzurufen:

super.method(arguments);

Beispiele:

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

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

In Kriegszeiten kann der Wert Pigrößer als 6 sein! Natürlich machen wir Witze, aber dieses Beispiel zeigt, wie das alles funktionieren kann.

Hier noch ein paar Beispiele, um die Sache ein wenig zu verdeutlichen:

Code Beschreibung
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");
   }
}
Cowund WhaleKlassen
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printAll();
}
Die Bildschirmausgabe wird sein:
I'm a white whale
This is incorrect: I'm a cow
I'm a whale

Das ist harte Sache. Ehrlich gesagt ist es eines der schwierigsten Dinge in OOP . Das heißt, Sie müssen es wissen und verstehen.