Hallo! In einer früheren Lektion haben wir die Umwandlung primitiver Typen besprochen. Erinnern wir uns kurz an das, was besprochen wurde.
Wir 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.
Betrachten Sie ein weiteres interessanteres Beispiel:
Mit Zahlen hat das geklappt – Probieren wir es mal! :) :)

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. int
Wenn wir versuchen, ein in eine Variable einzufügen short
, läuft es für uns nicht so reibungslos. Schließlich short
enthält die Variable nur 16 Bit an Informationen, eine int
belegt 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 short
Variable 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 Cat
und Dog
stehen 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 introduce
Methode der Pet
Klasse oder der Animal
Klasse 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 Pet
Referenz erweitert und einer Animal
Variablen 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 WildAnimal
Variable 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. 
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? 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 Animal
Objekt erstellt und versuchen, es einer Pet
Variablen 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 pet
Variable 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 Pet
Objekt, auf das eine Pet
Variable verweist. Später Animal
deutete eine Referenz auf genau dasselbe Objekt hin. Danach konvertieren wir animal
in 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 Animal
Objekt:
Pet pet = (Pet) new Animal();
Sie können einer Nachkommenvariablen kein Vorgängerobjekt zuweisen. Sie können das Gegenteil tun.
GO TO FULL VERSION