Part 9

Objekt Polymorphismus

Wir haben Situationen erlebt, in denen Variablen vom Referenztyp andere Typen haben als ihren eigenen. Zum Beispiel sind alle Objekte vom Typ Object, d.h. jedes gegebene Objekt kann zusätzlich zu seinem eigenen Typ als Object-Typ-Variable dargestellt werden.

String text = "text";
Object textString = "another string";
String text = "text";
Object textString = text;

In den obigen Beispielen wird eine String-Variable sowohl als String-Typ als auch als Object-Typ dargestellt. Auch wird eine String-Typ-Variable einer Object-Typ-Variable zugewiesen. Eine Zuweisung in die andere Richtung, d.h. die Einstellung einer Object-Typ-Variablen auf einen String-Typ, wird jedoch nicht funktionieren. Das liegt daran, dass Object-Typ-Variablen nicht vom Typ String sind.

Object textString = "another string";
String text = textString; // FUNKTIONIERT NICHT!

Worum geht es hier?

Zusätzlich zum ursprünglichen Typ jeder Variable kann jede Variable auch durch die Typen von Schnittstellen, die sie implementiert, und Klassen, die sie erbt, dargestellt werden. Die Klasse String erbt die Klasse Object, und daher sind String-Objekte immer vom Typ Object. Die Klasse Object erbt jedoch keine String-Klasse, daher sind Object-Typ-Variablen nicht automatisch vom Typ String. Sehen Sie sich die API-Dokumentation der String-Klasse genauer an, insbesondere den oberen Teil der HTML-Seite.
Ein Screenshot der String-Klassen-API-Dokumentation. Der Screenshot zeigt, dass die String-Klasse die Klasse Object erbt.

Die API-Dokumentation für die String-Klasse beginnt mit einer allgemeinen Überschrift, gefolgt vom Paket der Klasse (java.lang). Nach den Paketdetails folgt der Name der Klasse (Class String), gefolgt von der Vererbungshierarchie der Klasse.

  java.lang.Object
   java.lang.String

Die Vererbungshierarchie listet alle Klassen auf, die die gegebene Klasse geerbt hat. Geerbte Klassen werden in der Reihenfolge der Vererbung aufgelistet, wobei die zu untersuchende Klasse immer unten steht. In der Vererbungshierarchie der String-Klasse sehen wir, dass die String-Klasse die Object-Klasse erbt. In Java kann jede Klasse höchstens eine Klasse erben. Andererseits kann die geerbte Klasse eine andere Klasse geerbt haben. Daher kann eine Klasse indirekt mehr als eine einzige Klasse erben.

Die Vererbungshierarchie kann auch als Liste der verschiedenen Typen betrachtet werden, die die Klasse implementiert.

Das Wissen, dass Objekte viele verschiedene Typen haben können — z.B. vom Typ Object — vereinfacht die Programmierung. Wenn wir in einer Methode nur Methoden benötigen, die in der Klasse Object definiert sind, wie toString, equals und hashCode, können wir einfach Object als Typ des Methodenparameters verwenden. In diesem Fall können Sie die Methode für jedes Objekt als Parameter übergeben. Schauen wir uns dies anhand der Methode printManyTimes an. Die Methode erhält eine Variable vom Typ Object und die Anzahl der Ausgaben als Parameter.

public class Printer {

    public void printManyTimes(Object object, int times) {
        int i = 0;
        while (i < times) {
            System.out.println(object.toString());
            // oder System.out.println(object);

            i = i + 1;
        }
    }
}

Der Methode kann jedes beliebige Objekt als Parameter übergeben werden. Innerhalb der Methode printManyTimes hat das Objekt nur Zugriff auf die in der Klasse Object definierten Methoden, da das Objekt in der Methode als Object-Typ bekannt ist. Das Objekt kann tatsächlich ein anderer Typ sein.

Printer printer = new Printer();

String string = " o ";
List<String> words = new ArrayList<>();
words.add("polymorphism");
words.add("inheritance");
words.add("encapsulation");
words.add("abstraction");

printer.printManyTimes(string, 2);
printer.printManyTimes(words, 3);
Beispielausgabe

o o [polymorphism, inheritance, encapsulation, abstraction] [polymorphism, inheritance, encapsulation, abstraction] [polymorphism, inheritance, encapsulation, abstraction]

Lassen Sie uns mit der Betrachtung der API-Beschreibung der String-Klasse fortfahren. Der Vererbungshierarchie in der Beschreibung folgt eine Liste der von der Klasse implementierten Schnittstellen.

  All Implemented Interfaces:
  Serializable, CharSequence, Comparable<String>

Die String-Klasse implementiert die Schnittstellen Serializable, CharSequence und Comparable<String>. Eine Schnittstelle ist ebenfalls ein Typ. Laut der API-Beschreibung der Klasse können die folgenden Schnittstellen als Typ eines String-Objekts festgelegt werden.

Serializable serializableString = "string";
CharSequence charSequenceString = "string";
Comparable<String> comparableString = "string";

Da wir den Typ des Methodenparameters definieren können, können wir Methoden deklarieren, die ein Objekt erhalten, das eine bestimmte Schnittstelle implementiert. Wenn ein Methodenparameter eine Schnittstelle ist, kann jedes Objekt, das diese Schnittstelle implementiert, als Argument übergeben werden.

Wir erweitern die Klasse Printer, sodass sie eine Methode zum Ausgeben der Zeichen von Objekten hat, die die CharSequence-Schnittstelle implementieren. Die CharSequence-Schnittstelle stellt unter anderem die Methoden int length() zum Abrufen der Länge eines Strings und char charAt(int index) zum Abrufen eines Zeichens an einem bestimmten Index bereit.

public class Printer {

    public void printManyTimes(Object object, int times) {
        int i = 0;
        while (i < times) {
            System.out.println(object);
            i = i + 1;
        }
    }

    public void printCharacters(CharSequence charSequence) {
        int i = 0;
        while (i < charSequence.length()) {
            System.out.println(charSequence.charAt(i));
            i = i + 1;
        }
    }
}

Der Methode printCharacters kann jedes Objekt übergeben werden, das die CharSequence-Schnittstelle implementiert. Dazu gehören String sowie StringBuilder, die oft funktionaler für den Aufbau von Strings ist als String. Die Methode printCharacters gibt jedes Zeichen eines gegebenen Objekts in einer eigenen Zeile aus.

Printer printer = new Printer();

String string = "works";

printer.printCharacters(string);
Beispielausgabe

w o r k s

Loading
Loading
Sie haben das Ende dieses Abschnitts erreicht! Weiter zum nächsten Abschnitt: