Klassen beschreiben Entwurf und Implementierung.
Interfaces enthalten
Beispiel:
interface Verbose { int SILENT = 0; int VERBOSE = 1; void setVerbosity(int level); }
Anwendung:
class VerboseThing extends Thing implements Verbose { ... }
Aufgabe: Objekten von benutzerdefinierten Klassen sollen ein oder mehrere benannte Attribute zugeordnet werden.
z.B.
("Farbe", #ff00ff) ("transparent", false)
Zunächst: Der Typ Attr
public class Attr { private String name; private Object value; public Attr(String name) { this.name = name; } public Attr(String name, Object value) { this.name = name; this.value = value; } public String nameOf() { return name; } public Object valueOf() { return value; } public Object valueOf(Object newValue) { Object oldValue = value; value = newValue; return oldValue; } }
Idee:
Ein Typ Attributed mit folgender Funktionalität:
void add(Attr newAttr) Attr find(String AttrName) Attr remove(String AttrName)
Benutzertypen könnten diesen Typ Attributed erweitern und wären somit attributiert:
class Figure extends Attributed { ... }
Problem: Einfacherbung in Java verbietet dies im Normalfall, da der Benutzertyp bereits eine Oberklasse hat.
Einziger Ausweg: Einbau der gewünschten Funktionalität in die
Wurzelklasse Object. Geht nicht und ist auch nicht sinnvoll!
public interface Attributed { void add(Attr newAttr); Attr find(String attrName); Attr remove(String attrName); } class AttributedFigure extends WhatEver implements Attributed { ... }
Wir haben eine klare und einfache Lösung unseres Problems, können allerdings
die Implementierung von Attributed nicht erben, sondern müssen sie
selbst liefern.
zum Beispiel so:
import java.util.*; public class AttributedImpl implements Attributed { protected Hashtable attrTable = new Hashtable(); public void add(Attr newAttr) { attrTable.put(newAttr.nameOf(), newAttr); } public Attr find(String name) { return (Attr) attrTable.get(name); } public Attr remove(String name) { return (Attr) attrTable.remove(name); } }
zu Mehrdeutigkeiten.
Ursache für diese Mehrdeutigkeiten ist der Zugriff auf Implementierungsaspekte
(Attribute)
Also: Einfacherbung für Klassen
Mehrfacherbung von Entwurfsaspekten macht keine Probleme
Also: Mehrfacherbung für Interfaces
class AttributedFigure extends WhatEver implements Attributed, Verbose { ... }
public interface Verbose { ... }
Ein Interface ist abstrakt. Dies kann man durch abstract
kennzeichnen, ist aber überflüssig.
Ein Interface kann ein oder mehrere Ober-Interfaces ( Superinterfaces) haben:
interface X extends Y, Z { ... }
Die Superinterface-Beziehung darf natürlich weder direkt noch indirekt zyklisch sein.
Es gibt für Interfaces keine Analogie zur Wurzelklasse Object.
Interface-Elemente sind
Diese sind implizit public.
Weder public noch static und final für die Konstanten
brauchen spezifiziert zu werden.
interface Verbose { int SILENT = 0; int VERBOSE = SILENT+1; void setVerbosity(int level); }
Initialisierungsausdrücke werden ausgewertet, wenn das Interface geladen wird.
Es gelten die gleichen Regeln wie bei der Initialisierung von
Klassenvariablen
(Reihenfolge, kein this, etc., siehe Seite ).
D erbt ROT mehrmals: Kein Problem.
D erbt verschiedene Felder namens BLAU: Kein Problem, wenn
D BLAU nicht benutzt, ansonsten Fehlermeldung.
Implizit public und abstract. Verboten sind die Spezifikatoren static und final, wobei die Methode die eine Interface-Methode implementiert durchaus final sein darf.
Interface-Methoden können Methoden gleicher Signatur aus Ober-Interfaces
überschreiben . Fehler, wenn Ergebnistyp verschieden.
Ein Interface kann 2 Methoden gleicher Signatur erben. Kein Problem, wenn
der Ergebnistyp gleich ist.
Zwei Interface-Methoden mit gleichem Namen aber verschiedener Signatur
sind überladen . Ergebnistyp spielt dabei keine Rolle.
Aus ``Streifzug durch Java'' (Seite ):
Interfaces erweitern die Möglichkeiten der Polymorphie:
Die Obertypen einer Klasse T
umfassen
Ein Objekt vom Typ T darf überall dort verwendet werden, wo Obertypen
von T zulässig sind.
public interface Cloneable4
Klassen, die dieses Interface implementieren signalisieren der
Methode Object.clone(), daß ihre Objekte kopiert werden können
(elementweise Kopie).
clone()-Aufrufe für Objekte, deren Klassen dieses Interface nicht
implementieren, führen zu einer CloneNotSupportedException.
Jede Klasse, deren Instanzen als Thread ausgeführt werden sollen,
sollte Runnable implementieren.
public abstract void run() When an object implementing interface Runnable is used to create a thread, starting the thread causes the object's run method to be called in that separately executing thread.