web-dev-qa-db-fra.com

Java: remplacer la variable statique de la classe parente?

J'ai la classe suivante que j'utilise comme base de tous les modèles de mon projet:

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..
}

J'essaie alors de m'étendre de la manière suivante:

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

Cependant, si j'essaie de faire ce qui suit:

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

Ensuite, plutôt que la requête: "SELECT id FROM user WHERE id = ?", Il génère la requête: "SELECT id from null WHERE id =?". Ainsi, le remplacement du champ table dans la classe User ne semble pas avoir d'effet.

Comment surmonter cela? Si j'ai ajouté une méthode setTable() à BaseModel et que j'ai appelé setTable() dans le constructeur de User, la nouvelle valeur de table sera-t-elle disponible pour toutes les méthodes de la classe User également?

18
Click Upvote

Vous ne pouvez pas remplacer des méthodes statiques ou des champs de tout type en Java.

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

Cela crée un nouveau champ User#table qui se trouve avoir le même nom que BaseModel#table. La plupart des IDE vous en avertiront.

Si vous modifiez la valeur du champ dans BaseModel, il s'appliquera également à toutes les autres classes de modèle.

Une façon consiste à avoir les méthodes de base génériques

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();
}

et l'utiliser dans la sous-classe

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

Si vous souhaitez utiliser l'approche par champ, vous devez créer une classe BaseDAO et disposer d'un UserDAO (un pour chaque classe de modèle) qui définit le champ en conséquence. Ensuite, vous créez des instances singleton de tous les daos.

16
Cephalopod

Parce que Java ne vous permet pas de remplacer les membres static, vous devez essentiellement recourir à un peu plus verbeux mais globalement plus agréable modèle singleton , où vous écrivez toujours conceptuellement du code "statique", mais vous utilisez techniquement des instances (globales/singleton/"statiques"), donc vous n'êtes pas limité par les limitations de static.

(notez que vous devez également utiliser des méthodes car les champs ne participent pas au polymorphisme et ne peuvent donc pas être remplacés)

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);
}

Sorties:

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

Afin de faire ce que vous cherchez à faire, ne rendez pas table statique dans le BaseModel. Ensuite, dans les autres classes qui héritent de BaseModel, vous pouvez définir table dans le constructeur par défaut comme vous le souhaitez.

static {
    table = "user";
}
3
Brian Dishaw