CodeGym /Java-Blog /Random-DE /Erweiterung und Einengung von Referenztypen
Autor
John Selawsky
Senior Java Developer and Tutor at LearningTree

Erweiterung und Einengung von Referenztypen

Veröffentlicht in der Gruppe Random-DE
Hallo! In einer früheren Lektion haben wir die Umwandlung primitiver Typen besprochen. Erinnern wir uns kurz an das, was besprochen wurde. Erweiterung und Einengung von Referenztypen - 1Wir stellten uns primitive Typen (in diesem Fall numerische Typen) als Nestpuppen vor, deren Größe je nach der Menge an Speicher, die sie belegen, variiert. Wie Sie sich erinnern werden, ist es sowohl im wirklichen Leben als auch in der Java-Programmierung einfach, eine kleinere Puppe in eine größere zu stecken.

public class Main {
   public static void main(String[] args) {
       int bigNumber = 10000000;
       short smallNumber = (short) bigNumber;
       System.out.println(smallNumber);
   }
}
Dies ist ein Beispiel für eine automatische Konvertierung oder Erweiterung . Dies geschieht von selbst, sodass Sie keinen zusätzlichen Code schreiben müssen. Am Ende machen wir nichts Ungewöhnliches: Wir stecken einfach eine kleinere Puppe in eine größere Puppe. Eine andere Sache ist es, wenn wir das Gegenteil versuchen und eine größere russische Puppe in eine kleinere Puppe stecken. Im wirklichen Leben kann man das nicht machen, aber beim Programmieren schon. Aber es gibt eine Nuance. intWenn wir versuchen, ein in eine Variable einzufügen short, läuft es für uns nicht so reibungslos. Schließlich shortenthält die Variable nur 16 Bit an Informationen, eine intbelegt jedoch 32 Bit! Dadurch wird der übergebene Wert verfälscht. Der Compiler gibt uns eine Fehlermeldung („ Alter, du machst etwas Verdächtiges!“)'). Wenn wir jedoch explizit den Typ angeben, in den wir unseren Wert konvertieren, wird die Operation ausgeführt.

public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Genau das haben wir im obigen Beispiel getan. Die Operation wurde ausgeführt, aber da die shortVariable nur 16 der 32 Bytes aufnehmen kann, ist der Endwert verzerrt und wir erhalten die Zahl -27008 . Eine solche Operation wird als explizite Konvertierung oder Eingrenzung bezeichnet .

Beispiele für die Erweiterung und Einengung von Referenztypen

Lassen Sie uns nun über dieselben Operatoren sprechen, die nicht auf primitive Typen angewendet werden, sondern auf Objekte und Referenzvariablen ! Wie funktioniert das in Java? Eigentlich ist es ganz einfach. Es gibt Objekte, die nichts miteinander zu tun haben. Es wäre logisch anzunehmen, dass sie weder explizit noch automatisch ineinander konvertiert werden können:

public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog(); // Error!

   }

}
Hier erhalten wir natürlich einen Fehler. Die Klassen Catund Dogstehen in keiner Beziehung zueinander und wir haben keinen „Konverter“ geschrieben, um von einer zur anderen zu wechseln. Es macht Sinn, dass wir das nicht können: Der Compiler hat keine Ahnung, wie er diese Objekte von einem Typ in den anderen konvertieren soll. Wenn die Objekte miteinander in Zusammenhang stehen, ist das eine andere Sache! Verwandte wie? Vor allem durch Vererbung. Versuchen wir, mithilfe der Vererbung ein kleines Klassensystem zu erstellen. Wir werden eine gemeinsame Klasse zur Darstellung von Tieren haben:

public class Animal {

   public void introduce() {

       System.out.println("I'm Animal");
   }
}
Jeder weiß, dass Tiere domestiziert (Haustiere) oder wild sein können:

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");
   }
}
Nehmen wir zum Beispiel Eckzähne – wir haben Haushunde und Kojoten:

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");
   }
}
Wir haben gezielt die grundlegendsten Klassen ausgewählt, um sie leichter verständlich zu machen. Wir brauchen eigentlich keine Felder und eine Methode reicht aus. Versuchen wir, diesen Code auszuführen:

public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Was wird Ihrer Meinung nach auf der Konsole angezeigt? Wird die introduceMethode der PetKlasse oder der AnimalKlasse aufgerufen? Versuchen Sie, Ihre Antwort zu begründen, bevor Sie weiterlesen. Und hier ist das Ergebnis! Ich bin Pet. Warum haben wir das bekommen? Es ist alles einfach. Wir haben eine übergeordnete Variable und ein untergeordnetes Objekt. Durch das Schreiben,

Animal animal = new Pet();
Wir haben eine PetReferenz erweitert und einer AnimalVariablen zugewiesen. Wie bei primitiven Typen werden Referenztypen in Java automatisch erweitert. Sie müssen keinen zusätzlichen Code schreiben, um dies zu erreichen. Jetzt haben wir ein untergeordnetes Objekt, das einer übergeordneten Referenz zugewiesen ist. Als Ergebnis sehen wir, dass der Methodenaufruf für die untergeordnete Klasse erfolgt. Wenn Sie immer noch nicht vollständig verstehen, warum dieser Code funktioniert, schreiben Sie ihn im Klartext um:

Animal animal = new DomesticatedAnimal();
Das ist doch kein Problem, oder? Stellen Sie sich vor, dass dies das wirkliche Leben ist und die Referenz lediglich ein Papieretikett mit der Aufschrift „Tier“ ist. Wenn Sie dieses Stück Papier nehmen und es am Halsband eines beliebigen Haustiers befestigen, ist alles in Ordnung. Schließlich ist jedes Haustier ein Tier! Der umgekehrte Prozess – das Verschieben des Vererbungsbaums nach unten zu den Nachkommen – führt zu einer Einengung:

public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Wie Sie sehen, geben wir hier deutlich die Klasse an, in die wir unser Objekt konvertieren möchten. Zuvor hatten wir eine WildAnimalVariable und jetzt haben wir eine Coyote, die sich weiter unten im Vererbungsbaum befindet. Es macht Sinn, dass der Compiler ohne explizite Angabe einen solchen Vorgang nicht zulässt, aber wenn wir den Typ in Klammern angeben, funktioniert alles. Erweiterung und Einengung von Referenztypen - 2Betrachten Sie ein weiteres interessanteres Beispiel:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal(); // Error!
   }
}
Der Compiler generiert einen Fehler! Aber warum? Weil Sie versuchen, ein übergeordnetes Objekt einer untergeordneten Referenz zuzuweisen. Mit anderen Worten, Sie versuchen so etwas zu tun:

DomesticatedAnimal domesticatedAnimal = new Animal();
Nun, vielleicht funktioniert alles, wenn wir explizit den Typ angeben, in den wir konvertieren möchten? Mit Zahlen hat das geklappt – Probieren wir es mal! :) :)

public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Ausnahme im Thread „main“ java.lang.ClassCastException: Tier kann nicht in Haustierfehler umgewandelt werden ! Der Compiler hat uns dieses Mal nicht angeschrien, aber am Ende hatten wir eine Ausnahme. Den Grund kennen wir bereits: Wir versuchen, ein übergeordnetes Objekt einer untergeordneten Referenz zuzuweisen. Aber warum genau kann man das nicht tun? Denn nicht alle Tiere sind domestizierte Tiere. Sie haben ein AnimalObjekt erstellt und versuchen, es einer PetVariablen zuzuweisen. Ein Kojote ist ebenfalls ein Kojote Animal, aber er ist kein Kojote Pet. Mit anderen Worten, wenn Sie schreiben

Pet pet = (Pet) new Animal();
new Animal()könnte jedes Tier darstellen, nicht unbedingt ein Haustier! Natürlich eignet sich Ihre Pet petVariable nur für die Speicherung von Haustieren (und deren Nachkommen) und nicht für beliebige Tierarten. Aus diesem Grund wurde eine spezielle Java-Ausnahme, ClassCastException, für Fälle erstellt, in denen beim Umwandeln von Klassen ein Fehler auftritt. Schauen wir es uns noch einmal an, um es klarer zu machen. Eine übergeordnete Referenz kann auf Instanzen einer untergeordneten Klasse verweisen:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Hier haben wir zum Beispiel keine Probleme. Wir haben ein PetObjekt, auf das eine PetVariable verweist. Später Animaldeutete eine Referenz auf genau dasselbe Objekt hin. Danach konvertieren wir animalin eine Pet. Übrigens, warum hat das bei uns funktioniert? Beim letzten Mal gab es eine Ausnahme! Denn dieses Mal ist unser ursprüngliches Objekt ein Pet!

Pet pet = new Pet();
Aber im letzten Beispiel war es ein AnimalObjekt:

Pet pet = (Pet) new Animal();
Sie können einer Nachkommenvariablen kein Vorgängerobjekt zuweisen. Sie können das Gegenteil tun.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION