Redundante Deklarationen in abstrakten Klassen

Status
Nicht offen für weitere Antworten.

sliwalker

Top Contributor
Hoi,

ich bereite mich gerade auf eine Prüfung vor und bin auf einen Sachverhalt gestoßen, wozu ich gerne ein paar Meinungen hören würde. Es geht um folgenden Code:

Code:
public class ConcreteClass extends SecondAbstractClass {

    @Override
    public void doSomething() {
	System.out.println("I am doing something.");
    }
    
    public static void main(String[] args) {
	ConcreteClass c = new ConcreteClass();
	c.doSomething();
	c.someStuff();
    }
}

abstract class FirstAbstractClass {

    public abstract void doSomething();
}

abstract class SecondAbstractClass extends FirstAbstractClass {
    
    public abstract void doSomething();
    public void someStuff() {
	System.out.println("Some stuff between.");
    }
}

Man sieht hier, dass die erste Ableitung der FirstAbstractClass, nämlich die SecondAbstractClass, genau die gleiche Methode vorgibt, sie also nicht funktionell macht, sondern nur nochmal das bestätigt, was in der Superklasse steht.
Was soll ich davon halten?

Mir schwirren so Sachen im Kopf, dass ich eine Meldung bekommen sollte, dass es die Methode schon gibt. Oder ist es eh Wurst, weil es in der Form ja nichts kaputt macht? Ich schreibe es nur nochmal hin, hab vielleicht später nur Probleme, wenn ich mal die Signatur in FirstAbstractClass ändere, weil ich dann plötzlich in der ConcreteClass zwei Methoden haben müsste.

Das war eine Lücke in der Erklärung des Buches und das Beipsiel zeigt, dass es geht.
Könnt ihr mal was dazu sagen?

greetz
SLi
 
Zuletzt bearbeitet:
S

SlaterB

Gast
damit du noch mehr zum grübeln hast, gibt's das ganze auch bei Interfacen
Java:
interface A
{
    public void x();
}


interface B
    extends A
{
    public void x();
}

abstrakte Methoden sind ja quasi auch Interface

warum es so ist, kann ich nicht sagen,
Unabhängigkeit der Typen, 'macht nix kaputt' wie du schon sagst
 

SchonWiederFred

Bekanntes Mitglied
Ich schreibe es nur nochmal hin, hab vielleicht später nur Probleme, wenn ich mal die Signatur in FirstAbstractClass ändere, weil ich dann plötzlich in der ConcreteClass zwei Methoden haben müsste.
Du kannst dem Compiler einen Hinweis geben, dass Du keine neue Methode möchtest:
Java:
abstract class SecondAbstractClass extends FirstAbstractClass {

    @Override
    public abstract void doSomething();

    public void someStuff() {
        System.out.println("Some stuff between.");
    }
}
Wenn Du jetzt die Signatur in FirstAbstractClass änderst, gibt es einen Fehler zur Übersetzungszeit.
 

sliwalker

Top Contributor
Ja ok.
So mache ich es explizit deutlich.

Der Knackpunkt war jedoch, dass es sich so hinschreiben lässt.
Das es bei interfaces auch so ist, macht wenigstens Mut in Hinblick auf die Konsistenz der Dinge.
So muss man sich für abstract und interface nicht verschiedene Sachen merken.

Naja, nimmt mans mal so hin...
 

Landei

Top Contributor
Ich kann mir Fälle vorstellen, wo man doSomething() zuerst nur in SecondAbstractClass hat und später feststellt, dass die Methode auch in einem allgemeineren Kontext sinnvoll wäre, und sie deshalb auch in FirstAbstractClass voraussetzt. Dann sollte aber SecondAbstractClass ohne Änderungen oder Neucompilierung weiterlaufen können.
 

Marco13

Top Contributor
Teilweise sehe ich es als Problem an, dass es in Java keine private Vererbung gibt. Das kann nämlich zur Folge haben, dass nicht klar ist, "wo eine Methode herkommt". Je nachdem, um welche Klassen es dort genau ging, könnte es sein, dass die abstrakte Methode aus der FirstAbstractClass eigentlich nicht "offiziell" bekannt sein sollte. Sie dann nochmal in die zweite zu schreiben, kann dann deutlich machen, DASS sie bekannt sein sollte. Klingt wirr. Ein Beispiel? Schwierig...
Code:
abstract class Animal
{  
    abstract void eat();
}

abstract class Person extends Animal
{
    // abstract void eat(); // Um sowas geht's: Kann hier stehen oder nicht...
 
    abstract void work();
}

class Employee extends Person
{
    void eat() {  ... }
    void work() { ... }
}

class Company
{
    void method()
    {
        Employee e = getSomeEmployee();
        
        // Das ist OK
        e.work();
  
        // Ist das OK?
        e.eat();
    }
}
Die methoden, die von "Company" aufgerufen werden, beziehen sich auch unterschiedliche Ebenen der Vererbungshierarchie. work() steht in Employee. Bei "eat()" ist aber nicht mehr klar, ob diese Methode dafür gedacht war, von der Company aufgerufen zu werden, oder nur "zufällig mitvererbt" wurde. Ich finde, wenn man das
abstract void eat()
nochmal explizit in die Person-Klasse schreibt, ist das eine Möglichkeit, zu verdeutlichen, dass diese Methode von jedem aufgerufen werden können soll, der "Person" kennt.

Natürlich hat das keine wirklichen semantischen Unterschiede. Es ist eigentlich egal, ob es dasteht oder nicht. Aber als ... eine Art "Hinweis" kann man's IMHO hinschreiben.

Eine ähnliche Frage hatte ich schonmal gestellt ( http://www.java-forum.org/allgemein...mentierte-interfaces-nochmal-bei-impleme.html ) - da ging es darum, ob man bei

interface Interface {}
class ClassA implements Interface {}
class ClassB extends ClassA implements Interface {}

den Fettgegruckten Teil nochmal hinschreiben sollte oder nicht - eigentlich ist er überflüssig, aber es ist IMHO eine verbindliche(re) Aussage: "JA!!!, ClassB implementiert das (egal, ob sie es von ClassA erbt oder selbst implementiert)"
 

sliwalker

Top Contributor
Hoi,

bin auch eher der Fan davon alles nochmal hinzuschreiben, auch wenn es "klar" sein sollte.
Wenn man aber nun eine abstrakte Klasse mit 30 Methoden hat, ist es a) viel Arbeit, b) fehleranfällig.
Eine Änderung ganz oben muss überall unten drunter gemacht werden, sonst hast Du plötzlich eine neue Pflichtmethode. Deshalb würde ich hier fast eine Ausnahme machen und es nicht nochmal hinschreiben.

Das man irgendwann nur noch schwer erkennt wo es herkommt sehe ich ein, aber machbar und zumutbar ist es.
Zumutbar finde ich jedoch nicht in 6 abstrakten Klassen 10 Methodensignaturen ändern zu müssen. Haupteffekt des ganzen soll ja sein, Code wiederzuverwenden. Das würde man damit aushebeln.

Bei Deinem implements würde ich das gleiche sagen.
Denk Dir Du schiebst eine Hierachie dazwischen, weil Du merkst, dass interface kann zu wenig für manche Klassen und zuviel für andere. Also lässt Du Dein neues Interface erben. Da Du aber "sinnigerweise" alles doppelt geschrieben hast, hast Du ein Problem...

Ich glaube man muss sich da stark zwischen Lesbarkeit und Verständlichkeit und OO-Paradigmen entscheiden.
Ist glaube ich von Fall zu Fall unterschiedlich. Aber solange man sich noch über so etwas Gedanken macht, ist die Welt doch iO.

greetz
SLi
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben