wake-up-neo.com

Warum nicht abstrakte Felder?

Warum können Java-Klassen keine abstrakten Felder haben, wie sie abstrakte Methoden haben können?

Zum Beispiel: Ich habe zwei Klassen, die dieselbe abstrakte Basisklasse erweitern. Diese beiden Klassen haben jeweils eine Methode, die identisch ist, mit Ausnahme einer String-Konstante, die zufällig eine Fehlernachricht ist. Wenn Felder abstrakt sein könnten, könnte ich diese konstante Zusammenfassung machen und die Methode in die Basisklasse ziehen. Stattdessen muss ich eine abstrakte Methode mit dem Namen getErrMsg() erstellen, die den String zurückgibt, diese Methode in den beiden abgeleiteten Klassen überschreiben und dann die Methode aufrufen kann (die jetzt die abstrakte Methode aufruft).

Warum konnte ich nicht einfach das Feld abstrakt machen? Könnte Java dafür ausgelegt sein?

88
Paul Reiners

Sie können das tun, was Sie beschrieben haben, indem Sie ein abschließendes Feld in Ihrer abstrakten Klasse haben, das in ihrem Konstruktor initialisiert wird (ungeprüfter Code):

abstract class Base {

    final String errMsg;

    Base(String msg) {
        errMsg = msg;
    }

    abstract String doSomething();
}

class Sub extends Base {

    Sub() {
        super("Sub message");
    }

    String doSomething() {

        return errMsg + " from something";
    }
}

Wenn Ihre untergeordnete Klasse "vergisst", um das Finale durch den Superkonstruktor zu initialisieren, gibt der Compiler dies aus eine Warnung ein Fehler, genau wie wenn eine abstrakte Methode nicht implementiert ist.

86
rsp

Ich sehe keinen Sinn darin. Sie können die Funktion in die abstrakte Klasse verschieben und einfach ein geschütztes Feld überschreiben. Ich weiß nicht, ob dies mit Konstanten funktioniert, aber der Effekt ist der gleiche:

public abstract class Abstract {
    protected String errorMsg = "";

    public String getErrMsg() {
        return this.errorMsg;
    }
}

public class Foo extends Abstract {
    public Foo() {
       this.errorMsg = "Foo";
    }

}

public class Bar extends Abstract {
    public Bar() {
       this.errorMsg = "Bar";
    }
}

Ihr Punkt ist also, dass Sie die Implementierung/Überschreibung/was auch immer von errorMsg in den Unterklassen erzwingen wollen? Ich dachte, Sie wollten die Methode nur in der Basisklasse haben und wussten damals nicht, wie sie mit dem Feld umgehen sollen.

6
Felix Kling

Offensichtlich sollte könnte dafür ausgelegt worden sein, aber unter den Deckblättern müsste es noch einen dynamischen Dispatch und somit einen Methodenaufruf ausführen. Javas Design (zumindest zu Beginn) war zum Teil ein Versuch, minimalistisch zu sein. Das heißt, die Designer versuchten, das Hinzufügen neuer Features zu vermeiden, wenn sie von anderen Features, die bereits in der Sprache vorhanden sind, leicht simuliert werden können.

3

Eine andere Option besteht darin, das Feld in der Basisklasse als public (final, wenn Sie möchten) zu definieren und dieses Feld dann im Konstruktor der Basisklasse zu initialisieren, je nachdem, welche Unterklasse gerade verwendet wird. Es ist ein wenig zwielichtig, da es eine zirkuläre Abhängigkeit einführt. Aber es ist zumindest keine Abhängigkeit, die sich jemals ändern kann - d. H. Die Unterklasse ist entweder vorhanden oder nicht vorhanden, aber die Methoden oder Felder der Unterklasse können den Wert von field nicht beeinflussen.

public abstract class Base {
  public final int field;
  public Base() {
    if (this instanceof SubClassOne) {
      field = 1;
    } else if (this instanceof SubClassTwo) {
      field = 2;
    } else {
      // assertion, thrown exception, set to -1, whatever you want to do 
      // to trigger an error
      field = -1;
    }
  }
}
0
ragerdl

Beim Lesen Ihres Titels dachte ich, Sie beziehen sich auf abstrakte Instanzmitglieder. und ich konnte nicht viel für sie sehen. Aber abstrakte statische Mitglieder sind eine ganz andere Sache.

Ich habe mir oft gewünscht, dass ich in Java eine Methode wie die folgende deklarieren könnte:

public abstract class MyClass {

    public static abstract MyClass createInstance();

    // more stuff...

}

Grundsätzlich möchte ich darauf bestehen, dass konkrete Implementierungen meiner Elternklasse eine statische Factory-Methode mit einer bestimmten Signatur bereitstellen. Dies würde mir erlauben, einen Verweis auf eine konkrete Klasse mit Class.forName() zu bekommen und sicher zu sein, dass ich in einer Konvention meiner Wahl eine bauen kann.

0
Drew Wills