Abstrakte Methoden wie die hier:
[CODE lang="java" title="Tier Klasse"]public abstract class Tier {
public abstract void laufen();
}[/CODE]
[CODE lang="java" title="Katze"]public class Katze extends Tier{
@Override
void laufen(){
System.out.println("Katzen können laufen!");
}
}[/CODE]
Soweit so gut...
Aber wozu brauche ich die abstrakte Methode in der Tier Klasse? Ist die Zeile nicht unnötig?
// Wie müsste die Methode denn aussehen, damit es auch wirklich Sinn e gibt eine solche abstrakte Methode einzuführen?
Beste Antwort
K
kneitzel
Ja genau, damit ist dann sicher, dass alle Instanzen von einer Klasse, die von Tier erbt, diese Methode implementieren.
Wenn Du also eine Variable vom Typ Tier hast, dann kannst Du da laufen() drauf aufrufen.
Bei derart abstrakten Beispielen ist es immer schwierig direkt den Nutzen zu sehen. Abstrakte Klassen mit abstrakten Methoden werden dann verwendet wenn du Logik hast welche zwischen allen implementierenden Klassen ident sein soll. Nehmen wir dein Beispiel aber bauen es etwas um:
Wenn du jetzt eine Instanz von der Klasse "Tier" hast, kannst du immer "lautGeben" aufrufen ohne das du wissen musst welche konkrete Implementierung es tatsaechlich ist:
Java:
// instanceProvider ist eine Instanz einer Factory, also eine Klasse welche// die Instanz von "Tier" erzeugt ohne dass du weiszt welche konkrete// Implementierung es ist.Tier tier = instanceProvider.getTier();
tier.lautGeben();
In diesem Fall macht es natuerlich weniger Sinn eine abstrakte Klasse zu haben, sondern stattdessen eine Schnittstelle:
Interessant wird es dann wenn du Logik teilen willst, welche zwischen allen Implementierungen gleich sein wird. Da kannst du ebenfalls abstrakte Klassen verwenden wenn du das implementieren von Schnittstellen vereinfachen willst. Nehmen wir wieder unser Tier und nehmen an dass die Ausgabe von dem Laut nicht einfach nur "System.out.println" ist, sondern zum Beispiel eine Berechnung braucht und komplizierter ist. Jetzt will man nicht alle Implementierungen dazu zwingen den komplexen Code jedes mal neu zu erfinden, also gibt es zwei Moeglichkeiten:
Man packt den komplexen Code als "protected" Methode dazu:
Java:
publicabstractclassTier{publicabstractvoidlautGeben();protectedvoidlautMachen(String laut){// Stell dir hier komplexe Logik vor.}}publicclassKatzeextendsTier{@OverridepublicvoidlautGeben(){lautMachen("Miau");}}publicclassHundextendsTier{@OverridepublicvoidlautGeben(){lautMachen("Wuff");}}
Oder, insbesondere wenn man eine Schnittstelle dazu hat, verlagert man die zu implementierende Logik in abstrakte Methoden:
Java:
publicinterfaceTier{publicabstractvoidlautGeben();}publicabstractclassAbstractTierimplementsTier{@OverridepublicvoidlautGeben(){String laut =getLaut();// Stell dir hier komplexe Logik vor mit "laut".}protectedabstractStringgetLaut();}publicclassKatzeextendsTier{@OverrideprotectedvoidgetLaut(){return"Miau";}}publicclassHundextendsTier{@OverrideprotectedvoidgetLaut(){return"Wuff";}}
Die Verwendung von den Klassen hat sich nicht veraendert:
Aber der Unterschied ist hier wo man die Logik findet. Diese Schnittstelle + Abstrakte Klasse Kombination findet man oft wenn die konkreten Klassen viel Logik untereinander teilen. Dann packt man das was geteilt wird in die abstrakte Klasse und die konkrete Implementierung muss nur noch die Feinheiten anpassen. Ein relativ schoenes Beispiel ist auch eine Klasse welche einen Wert schreibt (wohin ist dem Verwender quasi egal), etwas konvolut in diesem Fall, aber bleib' mal bei mir. Folgender Aufbau:
Wenn du jetzt zum Beispiel eine Klasse brauchst welche in einen Netzwerk-Stream schreibt, musst du nicht das schreiben und die Stream-Verwaltung neu implementieren, sondern kannst dich von "AbstractStreamWriter" ableiten und musst nur noch den Stream erstellen.
Methoden die man in einem Interface definiert sind immer "public abstract". Man kann sie also auch nur mit Rückgabetyp, Namen und Parameterliste definieren.
Das andere ist ein kleiner Fehler im vorletzten Beispiel. Du schreibst: public class Katze extends Tier. Das sollte AbstractTier heißen. Darunter für class Hund nochmal dasselbe.
Und im letzten Beipiel fehlt bei public abstract class AbstractStreamWriter implements das "Writer".