首页 > 解决方案 > Java Generic 如何转换为子类型以调用泛型方法

问题描述

我有以下界面:

public interface EntityCloneService<T extends AbstractNamedEntityBase> {

 /**
  * Given a UUID load the Entity Type.
  * 
  * @param uuid
  * @return  Entity From DB and 
  */
 public T getByUuid(UUID uuid);


 /**
  * Given the Existing Entity,  clone it and save in DB, then return clone instance.
  */
 public T getCloneAndSave(T existingEntity) throws Exception;

}

现在我有通用服务,我有

@Component
public class GenericEntityCloneService {

    private static final Map<String,EntityCloneService<? extends AbstractNamedEntityBase>> registration = 
            new HashMap<String,EntityCloneService<? extends AbstractNamedEntityBase>>(); // here we have registration of all entity by name to service actual implementation.

    public void clone(AbstractNamedEntityBase existingEntity) {
        EntityCloneService<? extends AbstractNamedEntityBase> service = registration.get("SOME KEY");
        AbstractNamedEntityBase  entity =   service.getByUuid(ref.getUuid());  // THIS WORKS because it up casting.

        service.getCloneAndSave(entity);    // now how do I pass entity object such that 
    }
}

当我尝试编译此代码时无法编译。我知道 getCloneAndSave() 我正在传递不允许的类型 AbstractNamedEntityBase。那么如何拨打电话 service.getCloneAndSave(entity); 任何帮助是极大的赞赏。我正在使用java 8。

标签: javagenericsjava-8

解决方案


问题是这样的:

AbstractNamedEntityBase entity = service.getByUuid(ref.getUuid());

那条线丢弃T。每个 EntityCloneService 都与 AbstractNamedEntityBase 的一个子类一起工作。该服务的 getCloneAndSave 方法需要一个类型为 的对象T,它是AbstractNamedEntityBase的某个特定子类。

无法在 Map 中保留值的通用类型。你所知道的只是它是一个EntityCloneService<? extends AbstractNamedEntityBase>. 但是,您可以通过一些选项来解决它。

最简单的方法是在 EntityCloneService 中添加一个默认方法。在该接口内部,T是已知的,无需直接引用 AbstractNamedEntityBase:

default T getCloneAndSaveFor(UUID uuid)
throws Exception {
    T entity = getByUuid(uuid);
    return getCloneAndSave(entity);
}

另一种可能性是在 GenericEntityCloneService 中编写一个单独的方法,该方法知道每个 EntityCloneService 具有特定类型,即使该特定类型本身不知道:

private <E extends AbstractNamedEntityBase> E getCloneAndSaveFor(
    UUID uuid,
    EntityCloneService<E> service)
throws Exception {

    E entity = service.getByUuid(uuid);
    return service.getCloneAndSave(entity);
}

旁注:

  • throws Exception不是一个好习惯。不要强制调用者捕获旨在暴露程序员错误的未经检查的异常,例如 NullPointerException、IndexOutOfBoundsException、IllegalArgumentException 等。
  • 您可以将 Map 声明缩短为private static final Map<String,EntityCloneService<? extends AbstractNamedEntityBase>> registration = new HashMap<>();.

推荐阅读