Implementieren von mehreren Interfaces am Beispiel des Comparable-Interfaces

Wie wir in dem vorherigen Beitrag erfahren haben, gibt es in Java keine Mehrfachvererbung. Als Alternative zur Mehrfachvererbung können wir auf Interfaces zurückgreifen, da eine Klasse mehr als ein Interface implementieren kann.

Die Mehrfachimplementierung von verschiedenen Interfaces ist in Java durchaus üblich.

Dabei muss jede Klasse für jedes Interface alle darin deklarierten Methoden implementieren.

Implementiert eine Klasse ein Interface, wird sie dabei automatisch zu diesem Interface-Datentyp kompatibel. Eine Klasse kann daher zu mehreren Datentypen kompatibel sein.

In Java ist eine Klasse kompatibel zu:

  • dem Datentyp ihrer eigenen Klasse
  • den Datentypen ihrer n-Superklassen
  • den Datentypen ihrer m-Interfaces, die sie implementiert

Somit ist eine Klasse zu (n + m + 1) Datentypen kompatibel.

Mehrfachimplementierung am Beispiel des Comparable-Interfaces

Android Apps Programmieren Online-Kurs

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Wir möchten nun eine Beispielanwendung programmieren, die zwei Interfaces implementiert. Dabei möchten wir das Java Interface Comparable vorstellen, durch das unterschiedliche Objekte miteinander verglichen werden können.

Mit Hilfe von Interfaces werden Eigenschaften ausgedrückt, die auf Klassen aus unterschiedlichen Klassenhierarchien zutreffen.

Daher werden Interfaces oft mit Hilfe von substantivierten Adjektiven (Eigenschaftswörtern) benannt, so wie das Interface Comparable aus der Java-Klassenbibliothek, das sich in dem Paket java.lang befindet.

Das Comparable-Interface enthält die abtrakte Methode compareTo(Object obj), die einen int-Wert zurückliefert. Die Methode vergleicht das aufgerufene Objekt mit dem als Argument übergebene Objekt und liefert:

  • kleiner 0, falls das Objekt kleiner als das übergebene Argument ist,
  • gleich 0, falls es gleich groß ist und
  • größer 0, falls es größer ist zurück.

Die Klassen String und Character implementieren das Comparable-Interface standardmäßig.


Wir wollen nun das Comparable-Interface dazu verwenden, um unsere Klassen Tisch und Schaf miteinander vergleichbar zu machen. Dazu werden wir das Interface für beide Klassen implementieren. Das zweite Interface Transportierbar haben wir bereits in dem vorherigen Beitrag (Interfaces – Verwendung von Schnittstellen in Java) implementiert und können daher die entsprechenden Methodenimplementierungen unverändert übernehmen.

Beispielanwendung: Tisch-Klasse Mehrfachimplementierung

/*
* Beispielanwendung: Tisch-Klasse implementiert das Transportierbar- und Comparable-Interface
*/

public class Tisch implements Transportierbar, Comparable
{
  public String kennzeichnung;
  public boolean zerbrechlich;
  public float gewicht, laenge, hoehe, breite;

  public Tisch (String name, boolean zerbrechlich, float gewicht, float laenge, float breite, float hoehe)
  {
    kennzeichnung = name;
    this.zerbrechlich = zerbrechlich;
    this.gewicht = gewicht;
    this.laenge = laenge;
    this.breite = breite;
    this.hoehe = hoehe;
  }

  public float gewicht()
  {
    return gewicht;
  }
  public float laenge()
  {
    return laenge;
  }
  public float breite()
  {
    return breite;
  }
  public float hoehe()
  {
    return hoehe;
  }
  public boolean zerbrechlich()
  {
    return zerbrechlich;
  }
  public String beschriftung()
  {
    String text = "Tisch " + kennzeichnung;

    return text;
  }

  public int compareTo(Object obj)
  {
    float breite = 0;
    int ergebnis = 0;
    
    if (obj instanceof Tisch)
    {
      breite = ((Tisch) obj).breite;
    }
    if (obj instanceof Schaf)
    {
      breite = ((Schaf) obj).breite;
    }
    
    if (this.breite < breite)
    {
      ergebnis = -1;
    }
    else if (this.breite > breite)
    {
      ergebnis = 1;
    }

    return ergebnis;
  }
}

Mit der Implementierung des Comparable-Interfaces sind Objekte der Klasse Tisch jetzt sowohl zu dem Datentyp Comparable als auch zu Transportierbar kompatibel.

Als nächstes werden wir das Comparable-Interface auch für die Klasse Schaf implementieren:

Beispielanwendung: Schaf-Klasse Mehrfachimplementierung

/*
* Beispielanwendung: Schaf-Klasse implementiert das Transportierbar- und Comparable-Interface
*/

public class Schaf implements Transportierbar, Comparable
{
  public String name;
  public boolean zerbrechlich;
  public float gewicht, laenge, hoehe, breite;

  public Schaf (String name, boolean zerbrechlich, float gewicht, float laenge, float breite, float hoehe)
  {
    this.name = name;
    this.zerbrechlich = zerbrechlich;
    this.gewicht = gewicht;
    this.laenge = laenge;
    this.breite = breite;
    this.hoehe = hoehe;
  }

  public float gewicht()
  {
    return gewicht;
  }
  public float laenge()
  {
    return laenge;
  }
  public float breite()
  {
    return breite;
  }
  public float hoehe()
  {
    return hoehe;
  }
  public boolean zerbrechlich()
  {
    return zerbrechlich;
  }
  public String beschriftung()
  {
    String text = "Lebewesen: Schaf " + name;

    return text;
  }

  public int compareTo(Object obj)
  {
    float breite = 0;
    int ergebnis = 0;
    
    if (obj instanceof Tisch)
    {
      breite = ((Tisch) obj).breite;
    }
    if (obj instanceof Schaf)
    {
      breite = ((Schaf) obj).breite;
    }
    
    if (this.breite < breite)
    {
      ergebnis = -1;
    }
    else if (this.breite > breite)
    {
      ergebnis = 1;
    }

    return ergebnis;
  }
}

Somit sind nun auch die Instanzen der Klasse Schaf kompatibel zu den Datentypen Comparable und Transportierbar.

Das Interface Transportierbar wurde bereits in dem vorherigen Beitrag definiert. Zur Vollständigkeit wird der Quellcode hier nochmals angegeben:

Beispielanwendung: das Interface Transportierbar

/*
* Beispielanwendung: das Interface Transportierbar
*/

public interface Transportierbar
{
  public final float MAX_GEWICHT_PRO_FLAECHE = 29.99F;
  // hier geht auch: float MAX_GEWICHT_PRO_FLAECHE = 29.99F; 

  // alle Methoden in Interfaces sind implizit public und abstract
  // alle vier Methodendeklarationen sind zulässig
  // jede dieser Methoden ist public und abstract
  float gewicht(); 
  abstract float laenge();
  public float breite();
  public abstract float hoehe();

  boolean zerbrechlich();
  String beschriftung();
}

Jetzt wollen wir unsere neuen Klassenimplementierungen testen und die Objekte miteinander vergleichen. Dazu verwenden wir die compareTo-Methode als gemeinsame Schnittstelle.

Mit Hilfe der folgenden Klasse führen wir unsere Tests aus:

Beispielanwendung: Die Testklasse für die Mehrfachimplementierung

/*
* Beispielanwendung: die Testklasse für die Mehrfachimplementierung
*/

public class InterfaceTest
{
  public static void main (String[] args)
  {
    // erzeugen mehrerer Tisch- und Schaf-Objekte
    Tisch tischTisch     = new Tisch ("Esstisch", false, 27.3F, 3.0F, 2.2F, 1.3F);
    Transportierbar transpTisch = new Tisch ("Tisch", false, 15.0F, 2.0F, 1.5F, 1.0F);
    Comparable compTisch = new Tisch ("Nachtisch", false, 22.5F, 1.4F, 1.4F, 0.8F);
    Object objTisch      = new Tisch ("Kindertisch", false, 12.2F, 1.0F, 1.1F, 1.2F);

    Schaf schafSchaf            = new Schaf ("Cloud", true, 42.9F, 1.1F, 0.82F, 0.55F);
    Transportierbar transpSchaf = new Schaf ("Zara", true, 38.5F, 1.05F, 0.75F, 0.52F);
    Comparable compSchaf        = new Schaf ("Othello", true, 39.5F, 1.1F, 0.8F, 0.5F);


    int a = tischTisch.compareTo(objTisch);
    System.out.println("\nVergleich tischTisch mit objTisch:    " + a);

    // die folgende Zuweisung liefert einen Compiler-Fehler, da die
    // compareTo-Methode in der Klasse Object nicht vorhanden ist 
    // a = objTisch.compareTo(tischTisch);

    // die folgende Zuweisung liefert einen Compiler-Fehler, da die 
    // compareTo-Methode in dem Interface Transportierbar nicht vorhanden ist 
    // a = transpTisch.compareTo(tischTisch);

    a = schafSchaf.compareTo(tischTisch);
    System.out.println("Vergleich schafSchaf mit tischTisch: " + a);


    Comparable[] compObjects = new Comparable[4];
    compObjects[0] = tischTisch;
    compObjects[1] = compTisch;
    compObjects[2] = schafSchaf;
    compObjects[3] = compSchaf;

    // nur kompatible Referenzvariablen können in das Array compObjects, das sind 
    // Variablen vom Typ Schaf, Tisch und Comparable, da nur für diese auch
    // die Methode des Comparable-Interfaces bekannt und implementiert ist
    // compObjects[3] = transpTisch; // nicht erlaubt, da inkompatible Typen
    // compObjects[3] = objTisch;    // nicht erlaubt, da inkompatible Typen
    // compObjects[3] = transpSchaf; // nicht erlaubt, da inkompatible Typen

    a = compObjects[0].compareTo(compObjects[1]);
    System.out.println("\nVergleich tischTisch mit compTisch:   " + a);
    a = compObjects[1].compareTo(compObjects[0]);
    System.out.println("Vergleich compTisch mit tischTisch:  " + a);
    a = compObjects[2].compareTo(compObjects[3]);
    System.out.println("Vergleich schafSchaf mit compSchaf:   " + a);
    a = compObjects[3].compareTo(compObjects[1]);
    System.out.println("Vergleich compSchaf mit compTisch:   " + a);

 
    Transportierbar[] transpObjects = new Transportierbar[4];
    transpObjects[0] = schafSchaf;
    transpObjects[1] = transpSchaf;
    transpObjects[2] = tischTisch;
    transpObjects[3] = transpTisch;

    // nur kompatible Referenzvariablen können in das Array transpObjects, das sind 
    // Variablen vom Typ Schaf, Tisch und Transportierbar, da nur für diese auch
    // die Methoden des Transportierbar-Interfaces bekannt und implementiert sind
    // transpObjects[3] = compTisch; // nicht erlaubt, da inkompatible Typen
    // transpObjects[3] = compSchaf; // nicht erlaubt, da inkompatible Typen
    // transpObjects[3] = objTisch;  // nicht erlaubt, da inkompatible Typen

    // die folgende Zuweisung liefert einen Compiler-Fehler, da die
    // compareTo-Methode in dem Interface Transportierbar nicht vorhanden ist.
    // a = transpObjects[0].compareTo(compObjects[0]);
  }
}

Mit der oben angegebenen Testanwendung werden Objekte miteinander verglichen. Dabei ist es unbedeutend, welche Art von Objekten miteinander verglichen werden, solange sie alle das Interface Comparable implementieren.

Unsere Klassen Tisch und Schaf implementieren beide das Comparable-Interface, daher können sogar Instanzen dieser beiden Klassen untereinander verglichen werden.

Damit Objekte unterschiedlicher Klassen sinnvoll miteinander verglichen werden können, muss die Interfacemethode compareTo(Object obj) sinnvoll umgesetzt sein. In unserem Fall wird die Breite der Objekte miteinander verglichen.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

In unserer Beispielanwendung können Objekte miteinander verglichen werden, die kompatibel zu dem Comparable-Interface sind. Wie im Quellcode zu sehen, sind dass Instanzen der Klassen Tisch und Schaf. Diese Instanzen können in Referenzvariablen vom Typ Tisch, Schaf und Comparable gespeichert werden.

Hinweis: Der Typ der Referenzvariable ist von großer Bedeutung, da er vorgibt welche Methoden aufrufbar sind. Der Typ des darin gespeicherten Objekts gibt an welche Methodenversion (bei Methodenüberlagerung) zur Laufzeit aufgerufen wird.

Starten wir nun die Beispielanwendung. In der unteren Abbildung ist die Kommandozeilenausgabe des Programms dargestellt:

Java Interfaces Mehrfachimplementierung

Mehrfachimplementierung von Interfaces in Java – Ausgabe der Beispielanwendung

Hier geht es zurück zum Java Programmieren Lernen Kurs.


Comments 1

  1. Pingback: Interfaces (Schnittstellen) in Java

Schreibe einen Kommentar

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