Das Typcasting tritt grundsätzlich bei einer Wertzuweisung auf.
Eine Wertzuweisung wird immer dann gebraucht, wenn einer Variablen ein Wert zugewiesen werden soll.
variable = wert
Dabei ist zu beachten, dass die Typen auf der linken und rechten Seite vom Gleichheitszeichen identisch oder zumindest kompatibel sind. Ein Typcasting wird immer dann notwendig, wenn der zuzuweisende Wert einen anderen Typ hat als die Variable, in welcher er gespeichert werden soll.
Doch Obacht: man kann keine Typgleichheit erzwingen !
Das Beispiel
Bauen wir uns zunächst eine kleine Vererbungshierarchie mit zwei Klassen auf. Ein Hund ist ein Tier.

//code in java
class Tier {}
class Hund extends Tier {}
So weit, so gut.
Instanziierung von Objekten
Ein Objekt wird innerhalb des Programmsablaufs erzeugt.
Hund h = new Hund();
Tier t = new Tier();
Wir haben hier zwei Objektreferenzen h und t.
Die Referenz h zeigt auf ein Objekt vom Typ Hund. Für die Erzeugung des Objektes wird ein Konstruktor (hier: der Default-Konstruktor) der Klasse Hund verwendet.
Eine entsprechende Aussage können wir für die Objektreferenz t treffen.
Es ist aber nicht erforderlich, dass der Typ der Referenz und der für die Erzeugung des Objektes verwendete Konstruktor der gleichen Klasse entstammen, wie das in dem obigen Code der Fall ist.
Anwendung des Typcastings bei Vererbungshierarchien
Es gilt:
- der Typ einer Objektreferenz bestimmt, welche Eigenschaften und Methoden dem Objekt zugewiesen werden können.
- Der Konstruktor bestimmt die Implementierung der Methoden.
Insofern können wir auch folgende Codezeilen für die Instanziierung von Objekten verwenden:
Tier t2 = new Hund();
Hier wird aus einem speziellen Hund ein allgemeines Tier gemacht, da aufgrund der Vererbung jeder Hund ein Tier ist.
Was hingegen nicht funktioniert, ist:
Hund h2 = new Tier();
Aus einem allgemeinen Tier kann nicht ein Hund (als spezielles Tier) gemacht werden. Nicht jedes Tier ist automatisch ein Hund.
Typcasting bei Rückgabetypen von Methoden
Mit diesem Hintergrundwissen fangen wir nun an, etwas “zu spielen”. Klassen als Datentypen können als Übergabeparameter oder Rückgabetypen in Methoden verwendet werden. Das machen wir doch einfach mal.
Erstellen wir uns also eine Methode, die ein neues Objekt der Klasse Tier zurückgibt.
//code in java
public class Programm{
public static Tier getTier(){
return new Tier();
}}
Fügen wir der Klasse Programm nun eine main-Methode hinzu und nun rufen diese Methode auf. Die zurückgegebene Objektreferenz speichern wir in einer lokalen Variablen, die den gleichen Typ wie die Rückgabe der Methode getTier() hat.
public class Programm{
/* ... */
public static void main(String... args){
Tier referenz = getTier();
}}
Das funktioniert erst mal. Nun möchten wir aber nicht irgendein Tier, sondern einen Hund. Also versuchen wir, ein lokales Objekt der Klasse Hund zu erhalten. Ob das wohl funktioniert??
public class Programm{
/* ... */
public static void main(String... args){
Hund myHund = getTier();
}}
Compiler sagt nein … 🙁
Wenn wir uns vor Augen halten, dass auf rechten Seite der Zuweisung ein Objekt vom Typ Tier erstellt wird, können wir uns die Codezeile auch so vorstellen:
Hund myHund = new Tier(); //statt der Methode den Inhalt hingeschrieben
Und wir sehen: es wird versucht, ein allgemeines Tier in einem Hund zu transformieren (kann gutgehen, muss aber nicht – daher der Compilerfehler).
Passen wir unsere Methode an. Der Rückgabetyp wird die Klasse Hund sein.
public static Hund getTier(){
return new Hund();}
Auch hier werden wir nun die Operation in der main() aufrufen.
public static void main(String... args){
Hund myHund = getTier();
Tier myTier = getTier();
}
Durch die Änderung des Rückgabetyps in der Methode getTier() (und der Anpassung des return-Wertes) haben wir nun zwei Varianten, wie wir uns ein lokales Objektreferenz erschaffen können. Einmal, indem der Rückgabetyp der Methode mit dem Datentyp der lokalen Variable übereinstimmt (in beiden Fällen Hund) und zum anderen, indem wir als Datentyp für unsere lokale Variable eine generalisierte Klasse verwenden.
Als dritte Variante zum Rückgabetyp ändern wir unsere Methode nochmals ab. Man beachte hier, dass sich der Rückgabetyp Tier und der verwendete Konstruktor Hund unterscheiden.
public static Tier getTier(){
return new Hund();}
Und nun rufen wir die Methode auf.
public static void main(String... args){
Hund myHund = getTier(); //Zeile 1
Tier myTier = getTier();
}
Der Compiler wird auch hier eine Fehlermeldung bringen, die sich auf die Zeile 1 bezieht. Bei der Methode getTier() wird nun zwar intern ein Objekt der Klasse Hund erzeugt, aber der Rückgabetyp ist Tier (die generalisierte Klasse). Und der Compiler orientiert sich an den Typen (von der Objektreferenz myHund der Methode getTier). Und diese Typen müssen kompatibel sein.
Das sind sie in diesem Fall nicht. Bei Wertzuweisungen muss immer gelten:
- der Typ auf der linken Seite vom Gleichheitszeichen ist ausschlaggebend
- der Typ auf der rechten Seite vom Gleichheitszeichen entspricht dem Typ auf der linken Seite oder ist eine Spezialisierung von diesem
Abhilfe kann hier geschaffen werden, indem ein explizites Typcasting durchgeführt wird.
public static void main(String... args){
Hund myHund = (Hund) getTier(); //Zeile 1
Tier myTier = getTier();
}
Für den Compiler sind nun in dieser Zuweisung (Zeile 1) die Typen identisch und damit ist die Anweisung zulässt. Zur Laufzeit wird nun ein Casting des erzeugten Objektes vom Typ Tier durchgeführt.
Da für die Erzeugung der Konstruktor der Klasse Hund verwendet wurde, ist ein Casting wie in Zeile 1 vorgesehen möglich.
Typcasting bei Übergabeparametern von Methoden
So, und nun widmen wir uns noch der Verwendung von Klassen als Übergabeparameter in Methoden. Dazu erstellen wir uns eine Methode setTier(), welcher wir ein Objekt übergeben werden.
public class Programm{
/* ... */
public static void setTier(Tier t){}
}
Und nun auch hier ein Aufruf der Methode in der main().
public class Programm{
/* ... */
public static void main(String... args){
setTier(new Tier()); //erste Zeile
setTier(new Hund()); //zweite Zeile
}}
Wie wir sehen, gibt es zwei Möglichkeiten. Wir können sowohl ein Objekt der Klasse Tier (die erste Zeile) als auch ein Objekt der spezialisierten Klasse Hund (die zweite Zeile) übergeben. Das ist möglich, weil wir als Datentyp im Übergabeparameter die generelle Klasse Tier angegeben haben.
Und nun versuchen wir es anders … Wir wollen Compilerfehler 😉
Erst mal die Änderung der Methode
public static void setTier(Hund h){}
Und nun der Compilerfehler
public static void main(String... args){
setTier(new Hund()); //Zeile 1
setTier(new Tier()); //Zeile 2
}
Zeile 2 ist Schuld. Die Methode verlangt als Übergabeparameter eine Objektreferenz vom Typ Hund und wir übergeben ein allgmeines Tier.