# Überschreiben von Methoden erzwingen



## TSH (2. Feb 2009)

Hallo,

hat jemand eine Idee, wie ich das folgende realisiere? Essen machen soll im Prinzip für alle gleich ablaufen, die Art zu kochen soll aber jeder konkrete Koch überschreiben (müssen). Geht das?


```
public interface Koch {

  public machEssen();
  
}

public abstract class Abstract Koch implements Koch {

  public machEssen() {
    this.kaufeEin();
    this.koche();
    this.raeumAuf();
  }

  protected kaufeEin() {
    // Soll für alle gleich sein
  }

  protected koche() {
    // Hier möchte ich ein Überschreiben durch die konkreten Klassen erzwingen
  }

  protected raeumAuf() {
    // Soll für alle gleich sein
  }

}

public abstract class ChinesischerKoch extends AbstractKoch {

  // Essen machen an sich, einkaufen und aufräumen soll ererbt werden.
  // Nur die koche()-Methode, die beim Essen machen angewandt wird,
  // möchte ich überschreiben (und der Compiler soll schimpfen, wenn
  // ich's nicht tue.

  protected koche() {
    // Koche nach chinesischer Art
  }

}

public abstract class ItalienischerKoch extends AbstractKoch {

  // Wie oben.

  protected koche() {
    // Koche nach talienischer Art
  }

}
```


----------



## Spacerat (2. Feb 2009)

Recht einfach... In der abstrakten Klasse Koch die implementierung von "machEssen()" weglassen oder "koche()" als abstrakt markieren.

mfg Spacerat

@Edit: Bei genauerem Hinsehen stelle ich fest, das das Interface recht überflüssig ist. Die einzige Methode dieses Interfaces ist ja bereits vom abstrakten Koch implementiert. Das bedeutet:
-Interface weglassen,
-"machEssen()" public final
-"koche()" protected abstract
-alle anderen von "Koch" private final


----------



## TSH (2. Feb 2009)

Danke, aber mach essen enthält ja vieles, was für alle Köche gleich ist. Die einzelnen Methoden zum Einkaufen, Aufräumen und dem Essen-Kochen-Gesamtprozess würde ich schon gerne da drin lassen.

Sonst müsste ich ja alles x-mal implementieren.


----------



## SlaterB (2. Feb 2009)

Methoden, die nicht überschrieben werden dürfen, kann man als final deklarieren


----------



## Tobias (2. Feb 2009)

```
public interface Koch {

  public void machEssen(); // Ohne Rückgabewert (z.B. void) meckert der Compiler sowieso ;)
 
}

public abstract class AbstractKoch implements Koch {

  public void machEssen() {
    this.kaufeEin();
    this.koche();
    this.raeumAuf();
  }

  protected void kaufeEin() {
    // Soll für alle gleich sein
  }

  protected abstract void koche(); // abstract ist das Zauberwort!!

  protected void raeumAuf() {
    // Soll für alle gleich sein
  }

}

public class ChinesischerKoch extends AbstractKoch {

  // Essen machen an sich, einkaufen und aufräumen soll ererbt werden.
  // Nur die koche()-Methode, die beim Essen machen angewandt wird,
  // möchte ich überschreiben (und der Compiler soll schimpfen, wenn
  // ich's nicht tue.

  protected void koche() {
    // Koche nach chinesischer Art
  }

}

public class ItalienischerKoch extends AbstractKoch {

  // Wie oben.

  protected void koche() {
    // Koche nach talienischer Art
  }

}
```


----------



## TSH (2. Feb 2009)

(gelöscht. Muss erstmal die o.g. Antwort ausprobieren. Danke Euch allen schon mal!)


----------



## didjitalist (2. Feb 2009)

Spacerat hat gesagt.:
			
		

> -alle anderen von "Koch" private final


final kann man sich bei private methoden sparen. der einzige zweck wär nen hint an den compiler, die methode zu inlinen. aber das würd er, wenns angebracht ist, eh machen.


----------



## TSH (2. Feb 2009)

Danke! Das Interface ist aus anderen Gründen notwendig. Abstract war genau der Tipp, den ich gebraucht habe. Jetzt klappt es.


----------



## Spacerat (2. Feb 2009)

didjitalist hat gesagt.:
			
		

> final kann man sich bei private methoden sparen. der einzige zweck wär nen hint an den compiler, die methode zu inlinen. aber das würd er, wenns angebracht ist, eh machen.


Das ist definitiv falsch! Auch private Methoden können überschrieben werden (vgl. "Serializable" "readObject" und "writeObject"). Das einzige, was bei überlagerten Methoden dieser Art ausfällt, ist der Aufruf der überlagerten Methode der Superklasse. Ausserdem bringt "final" einen nicht zu verachtenden Performance-Vorteil. Ist aber alles nicht Teil des Themas... BTT

mfg Spacerat


----------



## SlaterB (3. Feb 2009)

werden diese Methoden bei Serializable nicht pro Klasse einzeln aufgerufen?
und das sowieso ohne Interface per Reflection, das zählt doch nicht als normales Beispiel


----------



## Spacerat (3. Feb 2009)

SlaterB hat gesagt.:
			
		

> werden diese Methoden bei Serializable nicht pro Klasse einzeln aufgerufen?
> und das sowieso ohne Interface per Reflection, das zählt doch nicht als normales Beispiel


Immer alles petzen . Aber ob nun Reflection oder nicht... Fakt ist doch, das die besagten Methoden "private" sind und möglicherweise irgendwann sogar überlagert werden müssen. So wie didjitalist das schreibt, klingt das aber so, das man sich bei "private"-Methoden das "final" sparen kann, weil sie eh' nicht überlagert werden können. Betrachtet am Beispiel "Serializable", bleibt diese Aussage immer noch definitiv falsch! Und hier macht "private final" eben deswegen Sinn, damit kein "Koch" jemals weder das "Einkaufen" noch das "Aufräumen" (durch überlagern der entsprechenden Methoden) vergisst.

mfg Spacerat


----------



## didjitalist (3. Feb 2009)

der performance vorteil von final rührt schlicht daher, dass für solche methoden polymorphie keine rolle spielt (virtual diskussion für c++ junkies), wenn ihr laufzeittyp konkret genug ist und der compiler sich mit höhrer wahrscheinlichkeit entscheiden wird, solche methoden daher sogar zu inlinen.

private methoden erfüllen diese kriterien ebenfalls. für sie spielt polymorphie keine rolle und wenn sie gerufen werden, ist immer ihr konkretes objekt am werk.

eine ausnahme bildet der zugriff über reflection, aber damit kann man so eine methode nicht plötzlich überlagern, nur rufen. readObject und writeObject sind dafür tatsächlich konkrete beispiele.


----------



## Spacerat (3. Feb 2009)

Was heisst denn "damit kann man so eine Methode nicht plötzlich überlagern"? Wie gesagt, hört sich nach wie vor so an, als könnte man es nicht. Dann erweitere mal ein "Serializable", welches die Schreib- und Lese-Methoden bereits implementiert hat. Wenn du nun eine eigene Implementation dieser Methoden brauchst hättest du in diesem Fall ein Problem, wenn du recht hättest (Irrtum).

```
public final class FaulerKoch
extends AbstractKoch
{
    protected void koche()
    {
        // wenn ich Zeit habe
    }

    private void kaufeEin()
    {
        // kein Geld
    }

    private void raeumeAuf()
    {
        // wozu?
    }
}
```
dieser Koch wird weder aufräumen noch einkaufen. Das ist möglich, weil der "AbstractKoch" ein überschreiben dieser Tätigkeit zulässt ("final" kann eben doch nicht weggelassen werden). Bevor du drauf antwortest... probier's aus... (Ich hab's getan... deswegen ist das kein Triezen, sondern mehr ein Tip, bevor du dich blamierst...)

mfg Spacerat


----------



## SlaterB (3. Feb 2009)

was genau ist eigentlich deine Aussage?
in

```
public class Test
{
    public static void main(String[] args)
        throws Exception
    {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bout);
        out.writeObject(new B());
    }
}


class A
    implements Serializable
{
    private final void writeObject(ObjectOutputStream out)
    {
        System.out.println("A writeObject");
    }
}


class B
    extends A
{
    private final void writeObject(ObjectOutputStream out)
    {
        System.out.println("B writeObject");
    }
}
```
erscheint als Ausgabe

```
A writeObject
B writeObject
```

zwei Dinge sind auf jeden Fall festzuhalten:
1. private-Methoden haben nichts mit Vererbung zu tun
und
2. private-Methoden haben nichts mit final zu tun,
ergibt sich quasi zwangsläufig, da final bei Methoden nur mit Vererbung zu tun hat

was ist denn dein Beispiel?

dass die protected-Methode koche() nicht final ist und deshalb überschrieben werden kann 
und dass ein FaulerKoch sämtliche private Methoden für sich neu deklarieren kann sind doch ganz andere Aussagen
(bzw. wieder zu final: mit final kann man nicht verhindern, was sich der faule Koch privat alles neu definiert)

da von 'blamieren' zu sprechen..


----------



## Gast (3. Feb 2009)

Sapcerat du laberst Unsinn, private Methoden kann man natürlich nicht überschreiben (überlagern ist übrigens was völlig anderes, weiß auch nich wieso du manchmal davon redest).
Dein Beispiel mit Serializable ist völliger Blödsinn, da
a) Interfaces weder private noch final Methoden haben können, wär ja auch sinnlos.
b) Serializable keine einzige Methode spezifiert, die ganze read/write Geschichte ist allein in der Dokumentation spezifiziert und der ganze Serialisierungskram wird mit Reflection gelöst. Hat nichts mit final oder private zu tun. Ob ich meine read/write Methoden private oder final mache ist übrigens egal.


----------



## SlaterB (3. Feb 2009)

inwiefern ist Überlagern was anderes als Überschreiben?


----------



## Leroy42 (3. Feb 2009)

Bei Überlagerung gibt es unterschiedliche Signaturen.


----------



## SlaterB (3. Feb 2009)

das ist Überladung, und das sollte doch der Anonyme erkennen


----------



## Spacerat (3. Feb 2009)

Ist es nicht so, das, wenn die privaten Methoden des AbstractKoch "final" wären, der Faule Koch gar nicht funktioniert, weil er eben "finale" Methoden überschreibt? Welche "kaufeEin" Methode wird denn von der JVM aufgerufen? die vom AbstractKoch oder die vom FaulenKoch? Doch wohl die vom faulen? Oder blamier ich mich jetzt hier?

mfg Spacerat


----------



## SlaterB (3. Feb 2009)

wenn AbstractKoch in seinen Methoden eine private Methode aufruft, dann ist es garantiert die eigene,
egal ob Subklassen gleichlautende Methoden definieren, ob privat oder nicht privat


----------



## Spacerat (3. Feb 2009)

Sch... so rum hab' ich das natürlich nicht gesehen. Hab' eigentlich immer angenommen, das die JVM mit der Instanzklasse zuerst arbeitet und deswegen die private Methode der Vaterklasse gar nicht mehr sieht. Naja... wieder was gelernt... Schwamm drüber...

mfg Spacerat


----------

