Java-Grundlagen: Typumwandlung bzw. Typkonvertierung (type casting) in Java

Android Apps Programmieren Online-Kurs

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Typumwandlung oder auch Typkonvertierung ist die Umwandlung eines Datentyps in einen anderen Datentyp.

Es ist dabei besonders darauf zu achten, dass beim Umwandeln keine Typverletzung entsteht, d.h. die beiden Datentypen müssen zueinander kompatibel sein.

Es gibt folgende Typumwandlungsarten:

  • Explizite Typumwandlung – bei der im Quellcode die Typumwandlung ausdrücklich angewiesen wird.

  • Implizite Typumwandlung – bei der die Typumwandlung nicht extra im Quelltext angewiesen wird, sondern automatisch vom Compiler durchgeführt wird.

Implizite Typumwandlungen können zu sehr schwerwiegenden Fehlern führen, wenn dabei Informationen verloren oder anders interpretiert werden.

Daher werden in Java implizite Typkonvertierungen nur dann durchgeführt, wenn diese ohne Informationsverlust erfolgen. Dabei muss der Ziel-Datentyp immer einen gleichen oder größeren Wertebereich als der Ausgangs-Datentyp besitzen.


Bei der Umwandlung eines Datentyps in einen Datentyp mit einem größeren Wertebereich spricht man von einer erweiternden Konvertierung (type promotion). Wird bei der Typumwandlung der Wertebereich verringert, dann spricht man von einer einschränkenden Konvertierung (type demotion) bei der gespeicherte Informationen verloren gehen können.

Konvertierungen von primitiven Datentypen in Java

Im Folgenden werden wir auf die Umwandlung von primitiven Datentypen eingehen. Bei den primitiven numerischen Datentypen erfolgt die Typumwandlung entweder als erweiternde Konvertierung oder als einschränkende Konvertierung.

In der folgenden Abbildung sind die Zusammenhänge unter den primitiven numerischen Datentypen ersichtlich:

Java Typumwandlung primitive Datentypen (type casting)

Java Typumwandlung von primitive Datentypen

Bei einer erweiternden Konvertierung wird ein Datentyp in einen weiter rechts stehenden Ziel-Datentyp umgewandelt, z.B. short-Datentyp in long-Datentyp. Wird gegen die Pfeilrichtung umgewandelt, also von rechts nach links, dann handelt es sich um eine einschränkende Konvertierung, z.B. von long-Datentyp nach float-Datentyp.

Hinweis: Eine Typumwandlung von dem boolean-Datentyp in einen anderen primitiven Datentyp ist nicht zulässig, ebenso ist eine Konvertierung von primitiven Datentypen und Referenz-Datentypen nicht möglich.

Da bei einer enschränkenden Konvertierung Informationen verloren gehen können, wird diese nicht automatisch von dem Compiler durchgeführt. Im Gegensatz dazu steht die erweiternde Konvertierung, diese wird vom Compiler automatisch vorgenommen, wenn:

  • eine Zuweisung erfolgt, bei der der Datentyp der Variable und des zugewiesenen Ausdrucks unterschiedlich sind,
  • Operanden eines arithmetischen Ausdrucks unterschiedlich typisiert sind,
  • bei einem Methodenaufruf die Datentypen der Parameter nicht identisch sind.

Wird in einem Subtraktionsausdruck ein byte– und int-Datentyp verwendet, so wandelt der Compiler den byte-Datentyp automatisch in einen int-Datentyp um. Da es sich um eine erweiternde Konvertierung handelt, gehen dabei auch keine Informationen verloren.

Möchte man jedoch einer int-Variable einen double-Datentyp zuweisen, dann wird die Typumwandlung, aufgrund von Informationsverlust, nicht automatisch durchgeführt. In diesem Fall müsste mit Hilfe des type-cast-Operators die einschränkende Typumwandlung explizit angewiesen werden.

Hinweis: Als Datentyp wird vom Compiler für den Array-Index ein int-Datentyp erwartet, daher können byte-, short– und char-Datentypen als Array-Index verwendet werden. Diese werden dann vom Compiler automatisch in den int-Datentyp konvertiert. Es ist jedoch nicht möglich den long-Datentyp als Array-Index zu verwenden, das hier eine einschränkende Konvertierung durchgeführt werden müsste.

Nun wollen wir die implizite und explizite Typumwandlung in Java mit Hilfe der folgenden Beispielanwendung näher betrachten:

Beispiel implizite und explizite Typumwandlung in Java.

/*
* Beispielanwendung implizite und explizite Typumwandlung in Java.
*/

public class TypumwandlungPrimitiv{
    public static void main(String[] args) {

        // Explizite Typumwandlung
        int valueInt     = 128;
        short valueShort = (short) valueInt;

        // Konvertierungsfehler, da Wertebereich von byte-Datentyp (-128, 127)
        byte valueByte   = (byte) valueInt;

        System.out.println("\nvalueInt:   " + valueInt);
        System.out.println("valueShort: " + valueShort);
        System.out.println("valueByte:  " + valueByte);
 
        // Implizite Typumwandlung
        valueShort = 2013;
        float valueFloat = valueShort;

        System.out.println("\nvalueShort: " + valueShort);
        System.out.println("valueFloat: " + valueFloat);
 
        // Konvertierungsfehler bei impl. Typumwandlung nach arithm. Ausdruck
        valueShort = 23;
        valueFloat = valueShort/2;

        System.out.println("\nvalueShort: " + valueShort);
        System.out.println("valueFloat: " + valueFloat);

        // kein Konvertierungsfehler da arithm. Ausdruck korrekt angegeben
        valueShort = 23;
        valueFloat = valueShort/2.0F;

        System.out.println("\nvalueShort: " + valueShort);
        System.out.println("valueFloat: " + valueFloat);

        // kein Konvertierungsfehler da arithm. Ausdruck durch explizite 
        // Typumwandlung korrekt angegeben
        valueShort = 23;
        valueFloat = valueShort/(float)2;

        System.out.println("\nvalueShort: " + valueShort);
        System.out.println("valueFloat: " + valueFloat);     
    }
}

In Zeile 10 wird der Wert der Variable valueInt explizit in einen short-Datentypwert umgewandelt. Dies geschieht mit Hilfe des type-cast Operators, der in den Klammern vor der Variable steht: short valueShort = (short) valueInt;.

In Zeile 13 wird der Wert der Variable valueInt explizit in einen byte-Datentypwert umgewandelt. Wieder mit Hilfe des type-cast Operators , der in den Klammern vor der Variable steht: byte valueByte = (byte) valueInt;. Da der Wertebereich des byte-Datentyps nur von -128 bis +127 reicht, gehen bei der einschränkenden Konvertierung Informationen verloren und der in Variable valueInt gespeicherte Wert wird falsch interpretiert. Dadurch wird der ursprüngliche Wert (128) als -128 ausgegeben. Siehe Zeile 17.

Weitere Informationen über die primitiven Datentypen und ihre Wertebereiche findet ihr in folgendem Beitrag: Die 2 Datentypenarten in Java und ihre Verwendung.

In Zeile 21 wird der Wert der Variable valueShort implizit in einen float-Datentypwert umgewandelt. Dies wird automatisch vom Compiler ausgeführt, da es sich um eine erweiternde Konvertierung handelt: float valueFloat = valueShort;.

In Zeile 28 wird zuerst das Ergebnis des arithmetischen Ausdrucks berechnet. Da der zweite Operand (2) eine Ganzzahl ist, wird eine Ganzzahldivison durchgeführt, deren Ergebnis 4 beträgt. Anschließend führt der Compiler eine implizite Typumwandlung von int auf double durch und die Variable zahlFloat weist den Wert 4.0 auf. Das richtige Ergebnis ist jedoch 4.5.

Um diesen Konvertierungsfehler zu vermeiden, muss der zweite Operand als Gleitkommazahl gekennzeichnet werden. Entweder indem man statt der 2 eine 2.0F (wie in Zeile 35) schreibt oder indem man eine explizite Typumwandlung anweist (wie in Zeile 43).

In der unteren Abbildung ist die Kommandozeilen-Ausgabe zu der oberen Beispielanwendung dargestellt.

Java Typumwandlung primitive Datentypen (type casting) Ausgabe

Java Typumwandlung von primitive Datentypen – Ausgabe der Beispielanwendung

Konvertierung von Referenztypen in Java

Typumwandlungen von Referenz-Datentypen unterscheiden sich von Umwandlungen der primitiven Datentypen darin, dass nicht die Objekte selbst verändert werden, sondern nur der Datentyp der entsprechenden Referenzen. Es wurd somit nur die Zugriffsart auf die Objekte geändert, dabei entstehen keine neuen Objekte.

Konvertierung von Referenztypen sind in Java nur bei Klassen erlaubt, die in Beziehung zueinander stehen. Und zwar muss die Typumwandlungen zwischen einer Vaterklasse und einer von ihr abgeleiteten Klasse erfolgen.

Die Umwandlung kann dabei in beide Richtung erfolgen.

Es gibt, wie bei den primitiven Typumwandlungen, wieder die beiden Typumwandlungsarten:

  • Explizite Typumwandlung – in Richtung der abgeleiteten Klasse, sie muss im Quellcode ausdrücklich angewiesen wird (einschränkende Konvertierung).
  • Implizite Typumwandlung – in Richtung der Vaterklasse, die Typumwandlung muss nicht extra im Quelltext angewiesen werden, sondern wird automatisch vom Compiler durchgeführt (erweiternde Konvertierung).

Die einschränkende Konvertierung ist jedoch nur bei Objekten möglich, die bereits der abgeleiteten Klasse angehörten und nur über eine allgemeinere Referenz angesprochen wurden.

Der Datentyp eines Java-Objekts wird immer im Objekt selbst mitgespeichert. Somit kann durch den Java-Interpreter während der Laufzeit der Datentyp des Objekts abgefragt und überprüft werden.

Um eine ClassCast-Exception zu vermeiden, sollte vor einer einschränkenden Typumwandlung immer mit dem instanceof-Befehl der Datentyp überprüft werden.

Ob die von der Typumwandlung betroffenen Klassen in einer Verwandschaftsbeziehung zueinander stehen, prüft der Compiler bereits im Vorfeld. Bei einer nicht zulässigen Typumwandlung, gibt der Compiler eine invalid cast Fehlermeldung aus.

Nun wollen wir die implizite und explizite Typumwandlung bei Referenz-Datentypen in Java mit Hilfe der folgenden Beispielanwendung näher betrachten:

Beispiel impl. und expl. Referenz-Typumwandlung in Java.

/*
* Beispielanwendung implizite und explizite Referenz-Typumwandlung in Java.
*/

import java.util.Vector;

public class TypumwandlungReferenz{
    public static void main(String[] args) {

        Object obj = new Object();
        String str = new String("Ein String-Objekt");

        System.out.println("\nobj:    " + obj);

        obj = str;

        System.out.println("\nobj:    " + obj);
        System.out.println("str:    " + str);


        obj = new Object();
        //str = obj; // Compilerfehler: incompatible types
        //str = (String) obj; // Laufzeitfehler: ClassCastException


        // impl. Typumwandlung String -> Object (in Richtung der Vaterklasse)
        Object objStr = new String("String-Objekt mit Object-Typ Referenz");

        System.out.println("\nobjStr: " + objStr);


        //str = objStr; // Compilerfehler: incompatible types
        str = (String) objStr; // nur möglich, da objStr eigentlich ein 
                               // String-Objekt ist

        System.out.println("\nstr:    " + str);


        Vector vec = new Vector();
        str = new String ("Ein neues String-Objekt");

        //vec = str; // Compilerfehler: incompatible types
        //vec = (Vector) str; // Compilerfehler: incompatible types, da Vector 
                              // und String nicht direkt miteinander verwandt

    }
}

In Zeile 10 wird das Object-Objekt obj und in Zeile 11 das String-Objekt str erzeugt. In Zeile 13 wird der Inhalt von obj ausgegeben, es ist die Referenz zum Objekt selbst.

In Zeile 15 wird eine implizite Typumwandlung in Richtung der Vaterklasse automatisch vom Compiler durchgeführt. Dies ist zulässig, da die String-Klasse von der Object-Klasse abgeleitet ist und es sich somit um eine erweiternde Konvertierung handelt.

In den Zeilen 17 und 18 wird der Inhalt der Objekte obj und str auf der Kommandozeile ausgegeben. In diesem Fall ist es die Zeichenkette „Ein String-Objekt“, da beide Referenz-Variablen auf das gleiche Objekt referenzieren.

Durch die Zuweisung in Zeile 21 referenziert die Referenz-Variable obj jetzt auf ein neues Object-Objekt. In Zeile 22 soll eine implizite Typumwandlung erfolgen, die jedoch nicht zulässig ist, da es sich hierbei um eine einschränkende Konvertierung handelt. Und zwar von der Vaterklasse Object in Richtung der abgeleiteten Klasse String. Der Compiler gibt eine incompatible types Fehlermeldung aus.

Auch die explizite Typumwandlung aus Zeile 23 ist nicht zulässig, da das Objekt auf das die Referenz-Variable obj referenziert selbst kein String-Objekt ist. Daher wird zur Laufzeit die ClassCast-Exception geworfen.

Anders sieht die Situation aus, wenn es sich um ein String-Objekt mit allgemeiner Referenz handelt. In Zeile 27 wird der Referenz-Variable objStr vom Datentyp Object ein neu erstelltes String-Objekt zugewiesen. Der Inhalt dieses Objekts wird in Zeile 29 ausgegeben.

Die implizite Typumwandlung in Zeile 32, ist nicht zulässig, da es sich hierbei um eine einschränkende Konvertierung handelt und wird vom Compiler nicht augeführt. Stattdessen wird eine incompatible types Fehlermeldung vom Compiler ausgegeben.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Mehr Erfolg bringt die explizite Typumwandlung aus Zeile 33. Zwar handelt es sich um eine einschränkende Konvertierung, von der Vaterklasse Object in Richtung der abgeleiteten Klasse String. Aber um eine zulässige Typumwandlung, da das Objekt auf das die Referenz-Variable objStr referenziert eigentlich ein String-Objekt ist.

In Zeile 36 wird der Inhalt von str ausgegeben, es ist die Zeichenkette „String-Objekt mit Object-Typ Referenz“.

In Zeile 39 wird eine Vector-Objekt erzeugt, auf das die Referenz-Variable vec referenziert, die selbst vom Typ Vector ist. Die Zuweisung aus Zeile 42 ist nicht zulässig. Es wird keine implizite Typumwandlung ausgeführt. Stattdessen wird eine incompatible types Fehlermeldung vom Compiler ausgegeben.

Auch die Zuweisung aus Zeile 43 ist nicht zulässig, da die Klassen Vector und String nicht direkt miteinander verwandt sind. Wiederum gibt der Compiler eine incompatible types Fehlermeldung aus.

In der unteren Abbildung ist die Kommandozeilen-Ausgabe zu der oberen Beispielanwendung dargestellt.

Java Typumwandlung Referenz Datentypen (type casting) Ausgabe

Java Typumwandlung von Referenz Datentypen – Ausgabe der Beispielanwendung


Comments 7

  1. Wird gegen die Pfeilrichtung umgewandelt, also von rechts nach links, dann handelt es sich um eine einschränkende Konvertierung, z.B. von long-Datentyp nach float-Datentyp.

    Kann es sein, das Du hier folgendes schreiben wollte.

    Wird gegen die Pfeilrichtung umgewandelt, also von rechts nach links, dann handelt es sich um eine einschränkende Konvertierung, z.B. von float-Datentyp nach long-Datentyp.

    Also von float nach long, das würde für mich die Pfeilrichtung von rechts nach links ergeben.

    1. Post
      Author

      Hallo,

      danke für den Hinweis.

      Gemeint ist eine Umwandlung von long (dem Datentyp mit größeren Wertebereich) nach float (dem Datentyp mit einem geringeren Wertebereich). Eine solche Umwandlung ist eine einschränkende Konvertierung, da der vorherige Wertebereich (long) nicht vollständig in den späteren Wertebereich (float) abgebildet werden kann.

      Viele Grüße, Chris

  2. Pingback: Variablen, Datentypen und Typumwandlung (type casting) in Java -

  3. Pingback: Java-Grundlagen: Besondere Operatoren in Java

  4. Pingback: Java-Grundlagen: Arithmetische Operatoren in Java

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.