Java Generic如何转换为子类型以调用泛型方法

时间:2018-12-04 02:06:04

标签: java generics java-8

我有以下界面:

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。

2 个答案:

答案 0 :(得分:1)

在这里,您同时将T用作生产者和消费者,因此在这里不能使用有界类型参数。您必须像这样使用方法级别的泛型,

public <S> S getCloneAndSave(S existingEntity) throws Exception;

答案 1 :(得分:1)

问题是这样的:

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<>();