Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用泛型的类调用了错误版本的方法(超类而不是子类)?_Java_Generics - Fatal编程技术网

Java 使用泛型的类调用了错误版本的方法(超类而不是子类)?

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

我试图重构一些代码,将几个缓存中共享的公共代码移动到基类中。这里有一个简化的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.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);
}
}