abstrakte Methoden, Schnittstellen

Eine Methode bezeichnet man als abstrakt, wenn sie noch nicht implementiert ist.


  public abstract class MacheZehnMal {

    public MacheZehnMal() {
      for (int i = 0;  i < 10;  i++) {
        aktion();
      }
    }

    public abstract void aktion();

  }

Diese Methode hat keinen Körper, sondern wird nur durch ein Semikolon abgeschlossen. Wenn eine Klasse abstrakte Methoden enthält, muss sie auch selbst als abstrakt deklariert werden. Das bedeutet, man kann keine Instanzen davon erstellen.

Nun ist es möglich diese Klasse zu überschreiben, inklusive der abstrakten Methode.


  public class Ausgabe extends MacheZehnMal {

    public void aktion() {
      System.out.println("Hello World.");
    }

  }

Wird eine neue Instanz durch new Ausgabe(); erstellt, erscheint die Ausgabe zehn mal auf dem Bildschirm. Ist kein Konstruktor angegeben, so wird automatisch der parameterlose Konstruktor erstellt, der den parameterlosen Konstruktor der Superklasse aufruft.

Sehr nützlich ist es in diesem Zusammenhang, dass Klassen 'inline' überschrieben werden können.


  new MacheZehnMal() {

    public void aktion() {
      System.out.println("Hello World.");
    }

  };

Dabei wird das Erstellen einer neuen (anonymen) Klasse mit dem Aufrufen des Konstruktors verbunden. Mehr dazu später im Thema Event-Handling und Adapter-Klassen.

Schnittstellen

Durch das Überschreiben von Methoden und aufgrund von Polymorphie ist es also möglich, das Verhalten einer Klasse zu ändern oder zu erweitern. Der Konstruktor der Beispielklasse verwendet etwa die Methode aktion(), obwohl sie noch nicht implementiert ist. Das funktioniert nur, weil eine Instanz dieser Klasse nicht direkt, sonder nur durch eine erbende Klasse erstellt werden kann, welche dann die Methode überschreibt und implementiert.

In diesem Fall muss aber zumindest der Sinn der abstrakten Methode bekannt sein, damit die eine Seite weiss, wozu und wann sie aufgerufen wird. Die andere Seite muss ebenfalls die Semantik wissen, um die Methode zu implementieren.

Nun kommt es häufig vor, dass eine Klasse nur aus abstrakten Methoden besteht. So eine Klasse kann als Schnittstelle (engl. Interface) deklariert werden. Dann kann man sich die ganzen Schlüsselworte, wie etwa abstract oder public sparen. Ein Interface kann aber keinen Konstruktor besitzen. Der Grund dafür liegt darin, dass Schnittstellen für Mehrfachverärbung in Java verwendet werden. Eine Klasse kann beliebig viele Schnittstellen implementieren. Innerhalb der Klasse muss aber eine eindeutige Super-Klasse existieren. Deshalb kann eine Klasse nur von einer anderen Klasse erben.


  class EineKlasse extends SuperKlasse implements Interface1, Interface2 {

    void foo() {
      super.bla();  // direkter Aufruf einer Methode aus SuperKlasse
    }

  }

'Wozu denn sowas?' werden sich einige Fragen. Das Prinzip ist aber schon von den Abstrakten Datenstrukturen aus EAD bekannt, etwa Stack und Queue.


  public interface Stack {

    void push(Object obj);
    Object pop();
    int size();

  }

  public interface Queue {

    void insertLast(Object obj);
    Object removeFirst();
    int size();

  }

Tatsächlich ist es möglich, dass eine Klasse beide Schnittstellen implementiert und als interne Datenstruktur ein Array oder eine Liste verwendet. Hier eine sehr einfache Variante:


  public class Sequence implements Stack, Queue {

    private Object[] a = new Object[100];
    private int size = 0;

    public void push(Object obj) {
      if (size < 100) {
        a[size++] = obj
      }
    }

    public Object pop() {
      return size > 0 ? obj[size--] : null;
    }

    public int size() {
      return size;
    }

    public void insertLast(Object obj) {
      push(obj);
    }

    public Object removeFirst() {
      if (size > 0) {
        Object temp = a[0];
        System.arraycopy(a, 1, a, 0, size - 1);
        size--;
        return temp;
      }
      return null;
    }

  }

Es gibt noch andere Varianten, eine Queue oder einen Stack zu implementieren. Etwa durch eine verkettete Liste, einen Baum oder was ganz anderes, was noch keinem eingefallen ist. Für das eigene Programm spielt dies aber keine (oder kaum eine) Rolle, es wird in allen Varianten gleich aussehen und nur auf den Datentyp Stack oder Queue zugreifen.


Erstellt von Markus Durzinsky, aktualisiert 2004-04-15
Für Fragen, Probleme oder Anregungen stehe ich gerne zur Verfügung