Java 使用泛型的类调用了错误版本的方法(超类而不是子类)?
我试图重构一些代码,将几个缓存中共享的公共代码移动到基类中。这里有一个简化的it概念:Java 使用泛型的类调用了错误版本的方法(超类而不是子类)?,java,generics,Java,Generics,我试图重构一些代码,将几个缓存中共享的公共代码移动到基类中。这里有一个简化的it概念: public abstract class DBObject { public void copyTo(DBObject other) { other.setId(this.id); } } public class Person extends DBObject { public void copyTo(Person other) { super.co
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...
}
}
公共抽象类DBObject{
public void copyTo(DBObject其他){
other.setId(this.id);
}
}
公共类Person扩展DBObject{
公共无效复制人(其他人){
super.copyTo(其他);
other.setName(this.name);
}
}
公共类PersonCache扩展缓存{
}
公共抽象类缓存{
地图idToCachedMap;
私人班;
公共无效初始化(){
//执行填充idToCachedMap的操作
}
public void updateCache(T cachedObjToUpdate){
T cachedObj=idToCachedMap.get(cachedObjToUpdate.getId());
T oldCachedObj=tObjectClass.newInstance();;
cachedObj.copyTo(oldCachedObj);//这里有问题
//做其他事情。。。
}
}
我遇到的问题是,当我在PersonCache上调用updateCache(Person)时,在对象上调用的copyTo方法是DBObject中的方法,而不是Person中的方法。因此,实际上只复制了部分数据(在本例中是ID,而不是名称)
在我看来,既然cachedObj和OldCachedObj都是Person对象(如果是PersonCache),那么应该调用的copyTo方法就是Person类上的方法
我觉得一定是泛型如何工作的原因导致了这种行为。我知道我是否将Person类中的copyTo重写为copyTo(DBObject other)而不是copyTo(Person other)的签名然后它确实在person类上调用了copyTo,但是重写它的方式太草率了,我想我缺少了一些更干净的东西。你说,在我看来,既然cachedObj和OldCachedObj都是person对象,如果它是PersonCache,应该调用的copyTo方法是Person类上的方法
由于类型擦除
这是一个错误的假设,在运行时它只知道DBObject
,显然也知道Object
它在运行时对T
一无所知,它被擦除,在运行时不可用
copyTo(T-other)
与copyTo(Person-other)
等效,由于类型擦除,它们重载而不被覆盖copyTo(T-other)
实际上变成了copyTo(DBObject-other)
,因为您的行为显示它与copyTo(DBObject-other)
匹配。这是预期的行为
类型擦除行为在SO和internet上都有很好的文档记录。在我看来,由于cachedObj和OldCachedObj都是Person对象(如果是PersonCache),因此应该调用的copyTo方法是Person类上的方法
由于类型擦除
这是一个错误的假设,在运行时它只知道DBObject
,显然也知道Object
它在运行时对T
一无所知,它被擦除,在运行时不可用
copyTo(T-other)
与copyTo(Person-other)
等效,由于类型擦除,它们重载而不被覆盖copyTo(T-other)
实际上变成了copyTo(DBObject-other)
,因为您的行为显示它与copyTo(DBObject-other)
匹配。这是预期的行为
类型擦除行为在SO和internet上都有很好的文档记录。您不会因为更改签名而覆盖
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);
}
}
公共抽象类DBObject{
公共无效复制到(T其他){
other.setId(this.id);
}
}
公共类Person扩展DBObject{
@凌驾
公共无效复制人(其他人){
super.copyTo(其他);
other.setName(this.name);
}
}
您没有因为更改签名而覆盖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);
}
}
公共抽象类DBObject{
公共无效复制到(T其他){
other.setId(this.id);
}
}
公共类Person扩展DBObject{
@凌驾
公共无效复制人(其他人){
super.copyTo(其他);
other.setName(this.name);
}
}