Java: переопределение статической переменной родительского класса?
У меня есть следующий класс, который я использую в качестве основы для всех моделей в моем проекте:
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..
}
Затем я пытаюсь перейти от него следующим образом:
public class User extends BaseModel
{
static String table = "user";
//snip
}
Однако, если я попытаюсь сделать следующее:
if ( User.exists( 4 ) )
//do something
Затем вместо запроса: "SELECT id FROM user WHERE id = ?"
создается запрос: "SELECT id from null WHERE id =?". Таким образом, переопределение поля table
в классе User
не имеет никакого эффекта.
Как я могу это преодолеть? Если я добавил метод setTable()
в BaseModel и вызвал setTable()
в конструкторе User
, будет ли новое значение table
доступно для всех методов класса User
?
Ответы
Ответ 1
Вы не можете переопределять статические методы или поля любого типа в Java.
public class User extends BaseModel
{
static String table = "user";
//snip
}
Это создает новое поле User#table
, которое просто имеет то же имя, что и BaseModel#table
. Большинство IDE предупредит вас об этом.
Если вы измените значение поля в BaseModel, оно применимо ко всем другим классам моделей.
Один из способов - использовать базовые методы generic
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();
}
и использовать его в подклассе
public static boolean exists(long id)
{
return exists("user", id);
}
Если вы хотите использовать полевой подход, вам нужно создать класс BaseDAO
и иметь UserDAO
(по одному для каждого класса модели), который соответствующим образом устанавливает поле. Затем вы создаете одиночные экземпляры всех даос.
Ответ 2
Поскольку Java не позволяет вам переопределять членов static
, вам в основном нужно прибегнуть к чуть более подробному, но в целом приятному singleton pattern, в котором вы по-прежнему концептуально пишете "статический" код, но вы технически используете (глобальные/одиночные/статические) экземпляры, поэтому вы не ограничены ограничениями static
.
(обратите внимание, что вам также нужно использовать методы, потому что поля не участвуют в полиморфизме и, следовательно, не могут быть переопределены)
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);
}
Выходы:
SELECT count(*) FROM user WHERE id = 123
SELECT count(*) FROM post WHERE id = 456
Ответ 3
Чтобы сделать то, что вы хотите сделать, не ставьте table
static в BaseModel
. Затем в других классах, которые наследуют от BaseModel
, вы можете установить table
в конструкторе по умолчанию на все, что пожелаете.
static {
table = "user";
}