【问题标题】:Class using generics is calling wrong version of method (superclass rather than subclass)? [duplicate]使用泛型的类调用错误版本的方法(超类而不是子类)? [复制]
【发布时间】:2015-05-21 18:16:37
【问题描述】:

我正在尝试重构一些代码,将在几个缓存之间共享的公共代码移动到一个基类。这是它的一个简化概念:

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 和 oldCachedObj 都保证是 Person 对象(如果它是 PersonCache),那么应该调用的 copyTo 方法就是 Person 类上的那个。

我觉得一定有一些关于泛型如何工作的东西我错过了导致这种行为。我知道如果我将 Person 类中的 copyTo 覆盖为 copyTo(DBObject other) 而不是 copyTo(Person other) 的签名,那么它确实会在 person 类上调用 copyTo - 但这是一种草率的重写方式我想我错过了一些可能更清洁的东西。

【问题讨论】:

    标签: java generics


    【解决方案1】:

    您没有覆盖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);
      }
    } 
    

    【讨论】:

      【解决方案2】:

      您说在我看来,既然 cachedObj 和 oldCachedObj 都保证是 Person 对象(如果它是 PersonCache),那么应该调用的 copyTo 方法是 Person 类上的方法。 p>

      因为type erasure 这是一个不正确的假设,在运行时它知道DBObject,显然Object 也是如此。

      它在运行时对T 一无所知,它被擦除并且在运行时不可用。

      copyTo(T other) 等同于 copyTo(Person other),由于类型擦除,它们被重载而不是覆盖copyTo(T other) 实际上变成了copyTo(DBObject other),因为您的行为表明它与copyTo(DBObject other) 匹配。这是预期的行为。

      类型擦除行为在 SO 和互联网上都有很好的记录。

      【讨论】:

        猜你喜欢
        • 2012-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-27
        • 2018-05-09
        • 2015-03-01
        • 2022-11-07
        • 1970-01-01
        相关资源
        最近更新 更多