Java: Statische Variable der übergeordneten Klasse überschreiben?

Lesezeit: 4 Minuten

Ich habe die folgende Klasse, die ich als Basis für alle Modelle in meinem Projekt verwende:

public abstract class BaseModel
{
    static String table;
    static String idField = "id";       

    public static boolean exists(long id) throws Exception
    {
        Db db = Util.getDb();
        Query q = db.query();
        q.select( idField ).whereLong(idField, id).limit(1).get(table);

        return q.hasResults();
    }

    //snip..
}

Ich versuche dann, daraus auf folgende Weise zu erweitern:

public class User extends BaseModel
{
    static String table = "user";
    //snip
}

Wenn ich jedoch versuche, Folgendes zu tun:

if ( User.exists( 4 ) )
   //do something

Dann statt der Abfrage: "SELECT id FROM user WHERE id = ?", erzeugt es die Abfrage: “SELECT id from null WHERE id = ?”. Also das Überschreiben der table Feld im User Klasse scheint keine Wirkung zu haben.

Wie überwinde ich das? Wenn ich ein hinzufüge setTable() -Methode zu BaseModel und aufgerufen setTable() im Konstruktor von Userdann wird der neue Wert von table stehen allen Methoden der zur Verfügung User Klasse auch?

Benutzer-Avatar
Kopffüßer

Sie können in Java keine statischen Methoden oder Felder jeglichen Typs überschreiben.

public class User extends BaseModel
{
    static String table = "user";
    //snip
}

Dadurch wird ein neues Feld erstellt User#table das hat zufällig den gleichen Namen wie BaseModel#table. Die meisten IDEs werden Sie davor warnen.

Wenn Sie den Wert des Felds in BaseModel ändern, gilt dies auch für alle anderen Modellklassen.

Eine Möglichkeit besteht darin, die Basismethoden generisch zu haben

protected static boolean exists(String table, long id) throws Exception
{
    Db db = Util.getDb();
    Query q = db.query();
    q.select( idField ).whereLong(idField, id).limit(1).get(table);

    return q.hasResults();
}

und verwenden Sie es in der Unterklasse

public static boolean exists(long id)
{
    return exists("user", id);
}

Wenn Sie den Feldansatz verwenden möchten, müssen Sie eine erstellen BaseDAO Klasse und habe eine UserDAO (eine für jede Modellklasse), die das Feld entsprechend festlegt. Dann erstellen Sie Singleton-Instanzen aller Daos.

  • Warum sollte eine IDE vor dem Verbergen von Daten warnen?

    – Rohit Jain

    18. Oktober 2013 um 19:00 Uhr

  • @Click: Ich habe meine Antwort erweitert.

    – Kopffüßer

    18. Oktober 2013 um 19:01 Uhr

  • exists() ist nur ein Beispiel, ich habe weitere 10-20 solcher Hilfsmethoden. Ich möchte nicht alle überladen, ich würde lieber nur die Eigenschaft des Tabellennamens ändern, damit sie alle funktionieren.

    – Ali

    18. Oktober 2013 um 19:02 Uhr

  • @Arian Es ist ein völlig erwartetes Verhalten. Es ist nur so, dass OP nicht damit gerechnet hat. OP spricht über das Überschreiben von Feldern, was nie gemacht wird. Nicht einmal zum Beispiel Feld.

    – Rohit Jain

    18. Oktober 2013 um 19:10 Uhr

  • “OP hat das nicht erwartet”, also war es unerwartet 😉 … außerdem, wer hat meine Antwort abgelehnt? Gib wenigstens einen Grund, Feigling!

    – Kopffüßer

    18. Oktober 2013 um 19:21 Uhr


Benutzer-Avatar
Erik Kaplun

Weil Java das Überschreiben nicht zulässt static Mitglieder, müssen Sie im Grunde auf die etwas ausführlichere, aber insgesamt nettere zurückgreifen Singleton-Musterwobei Sie konzeptionell immer noch “statischen” Code schreiben, aber technisch gesehen (globale/Singleton/”statische”) Instanzen verwenden, sodass Sie nicht durch die Einschränkungen von eingeschränkt sind static.

(Beachten Sie, dass Sie auch Methoden verwenden müssen, da Felder nicht am Polymorphismus teilnehmen und daher nicht überschrieben werden können.)

public abstract class BaseTable {
    public abstract String table();
    public String idField() { return "id"; }

    public boolean exists(long id) {
        // don't build queries this way in real life though!
        System.out.println("SELECT count(*) FROM " + table() + " WHERE " + idField() + " = " + id);
        return true;
    }
}

public class UserTable extends BaseTable {
    public static final User INSTANCE = new UserTable();
    private UseTabler() {}

    @Override public String table() { return "user"; }
}

public class PostTable extends BaseTable {
    public static final Post INSTANCE = new PostTable();
    private PostTable() {}

    @Override public String table() { return "post"; }
}

public static void main(String[] args) {
    UserTable.INSTANCE.exists(123);
    PostTable.INSTANCE.exists(456);
}

Ausgänge:

SELECT count(*) FROM user WHERE id = 123
SELECT count(*) FROM post WHERE id = 456

  • So würde es in Scala aussehen, wenn etwas naive Reflexion hinzugefügt wurde, ohne die Singleton-Boilerplate: pastebin.com/3iujwygZ

    – Erik Kaplun

    6. April 2014 um 14:45 Uhr


Benutzer-Avatar
Brian Dishaw

Um das zu tun, was Sie tun möchten, machen Sie es nicht table statisch in der BaseModel. Dann in den anderen Klassen, die davon erben BaseModelkönnen Sie einstellen table im Standardkonstruktor auf das, was Sie möchten.

static {
    table = "user";
}

  • Dann kann ich nicht anrufen User.exists() als statische Methode.

    – Ali

    18. Oktober 2013 um 19:10 Uhr

  • @ClickUpvote dies könnte ein Hinweis darauf sein, dass Sie die static Stichwort. Ich würde empfehlen, einen Blick auf Ihr Design zu werfen und es zu überarbeiten, um die Notwendigkeit für a zu beseitigen static exist()-Methode

    – StormeHawke

    18. Oktober 2013 um 19:14 Uhr

  • @StormeHawke Was ist falsch an meinem Design? Wird es klarer, wenn ich eine Instanz meines Benutzermodells erstellt habe, nur um zu überprüfen, ob die angegebene Benutzer-ID gültig ist?

    – Ali

    18. Oktober 2013 um 19:21 Uhr


  • @ClickUpvote Dort nicht sagen ist etwas stimmt mit Ihrem Design nicht, nur das da könnte sein Etwas, das Sie sich ansehen müssen, wenn Sie auf so etwas stoßen, bei dem das Design der Java-Sprache es Ihnen nicht erlaubt, das zu tun, was Sie tun möchten

    – StormeHawke

    18. Oktober 2013 um 19:22 Uhr

  • @ClickUpvote Sie könnten, wenn Sie den Standardkonstruktor des Benutzers ebenfalls statisch machen. Ich habe das nicht in mein Beispiel aufgenommen (Schande über mich), weil ich dachte, Sie würden sehen, dass dies die einzige Möglichkeit ist, wie es mit Ihrer aktuellen Implementierung funktionieren würde.

    – Brian Dishaw

    20. Oktober 2013 um 23:37 Uhr

1016080cookie-checkJava: Statische Variable der übergeordneten Klasse überschreiben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy