我正在尝试重构一些代码,将一些缓存中共享的公共代码移动到基类。这是一个简化的概念:
public abstract class DBObject {
public void copyTo(DBObject other) {
other.setId(this.id);
}
}
public class Person extends DBObject {
public void copyTo(Person other) {
super.copyTo(other);
other.setName(this.name);
}
}
public class PersonCache extends Cache<Person> {
}
public abstract class Cache<T extends DBObject> {
Map<Long, T> idToCachedMap;
private Class<T> tObjectClass;
public void initialize() {
// does stuff to populate the idToCachedMap
}
public void updateCache(T cachedObjToUpdate) {
T cachedObj = idToCachedMap.get(cachedObjToUpdate.getId());
T oldCachedObj = tObjectClass.newInstance();;
cachedObj.copyTo(oldCachedObj); // PROBLEM HERE
// do other stuff...
}
}
我遇到的问题是,当我在PersonCache上调用updateCache(Person)时,在对象上调用的copyTo方法是DBObject中的方法,而不是Person中的方法。因此,实际上只复制了一些数据(在本例中为ID,但不是名称)。
在我看来,由于cachedObj和oldCachedObjs都是Person对象(如果它是PersonCache),因此应调用的copyTo方法是Person类中的方法。
我觉得必须有一些关于我所缺少的仿制药如何工作导致这种行为。我知道如果我将Person类中的copyTo覆盖为copyTo(DBObject other)的签名而不是copyTo(Person other),那么它会在person类上调用copyTo - 但这是一种重写的方式它,我想我错过了一些可能更清洁的东西。
答案 0 :(得分:3)
您没有覆盖copyTo
方法,因为您更改了签名。并且您调用T
中存在的方法。
试试这个:
public abstract class DBObject<T extends DBObject> {
public void copyTo(T other) {
other.setId(this.id);
}
}
public class Person extends DBObject<Person> {
@Override
public void copyTo(Person other) {
super.copyTo(other);
other.setName(this.name);
}
}
答案 1 :(得分:2)
你陈述在我看来,既然cachedObj和oldCachedObjs都是Person对象,如果它是PersonCache,那么应该调用的copyTo方法就是Person类中的那个。
由于type erasure
这是一个不正确的假设,在运行时它知道的所有内容都是DBObject
,显然也是Object
。
它在运行时对T
一无所知,它已擦除并且在运行时不可用。
copyTo(T other)
不与copyTo(Person other)
重载而非重写等效。 copyTo(T other)
实际上变为copyTo(DBObject other)
,因为您的行为表明它与copyTo(DBObject other)
匹配。这是预期的行为。
类型擦除行为在SO和互联网上都有很好的记录。