Java泛型和枚举,模板参数丢失

我的结构相当复杂,无法正常工作。这是我所做的:

public interface ResultServiceHolder {

<M, ID extends Serializable, BO extends BusinessObject<M, ID>> ResultService<M, ID, BO> getService();

}

public enum ResultTypes implements ResultServiceHolder {

RESULT_TYPE_ONE {

@Override

public ResultOneService getService() { //unchecked conversion?

return serviceInitializer.getResultOneService();

}

},

RESULT_TYPE_TWO {

@Override

public ResultTwoService getService() { //unchecked conversion?

return serviceInitializer.getResultTwoService();

}

},

RESULT_TYPE_THREE {

@Override

public ResultThreeService getService() { //unchecked conversion?

return serviceInitializer.getResultThreeService();

}

};

protected ServiceInitializer serviceInitializer;

protected void setServiceInitializer(ServiceInitializer serviceInitializer) {

this.serviceInitializer = serviceInitializer;

}

@Component

public static class ServiceInitializer {

@Autowired

private ResultOneService resultOneService;

@Autowired

private ResultTwoService resultTwoService;

@Autowired

private ResultThreeService resultThreeService;

@PostConstruct

public void init() {

for(ResultTypes resultType : ResultTypes.values()) {

resultType.setServiceInitializer(this);

}

}

//getters

}

}

目的是根据枚举来概括调用,而只是能够迭代枚举数组。

    for(ResultServiceHolder resultServiceHolder : ResultTypes.values()) {

if(resultServiceHolder.equals(post.getPostResultTypeCode())) {

return resultServiceHolder.getService().createResultSearchCriteriaResponse(postId);

}

}

这工作正常且花花公子。但是,如果我说

ResultTypes.RESULT_TYPE_ONE.getService().getRepository()

那么它是一个BaseRepository<Object, Serializable>而不是一个BaseRepository<ResultTypeOne, Long>。该方法resultTypeHolder.getService()返回ResultService<M, ID, BO>,但最后,它变为ObjectSerializable

我究竟做错了什么?如何保留通用参数类型?

我要补充一点,是的,我确实意识到问题出在未经检查的转换问题上。但是服务定义为

public interface ResultTypeOneService

extends ResultService<ResultTypeOne, Long, ResultTypeOneBO> {

}

而且我不知道为什么不能推断类型。

编辑:从技术上讲,如果我明确推断出它们,则可以使用:

ResultTypes.RESULT_TYPE_ONE.<ResultTypeOne, Long, ResultTypeOneBO>getService().getRepository()

但是它应该是自动的,为什么它不能自动工作?我应该为它提供某种包含该类型的对象吗?为什么返回类型还不够呢?

EDIT2:的超类ResultTypeOne

@SuppressWarnings("serial")

@EntityListeners(EntityListener.class)

@MappedSuperclass

public abstract class EntityBase implements Serializable {

但是它没有映射到边界的任何地方。

EDIT3:非常感谢@Radiodef!理论解最终如下,并且可以很好地工作:

public interface ResultServiceHolder<M, ID extends Serializable, BO extends BusinessObject<M, ID>> {

ResultService<M, ID, BO> getService();

}

public abstract class ResultTypes<M, ID extends Serializable, BO extends BusinessObject<M, ID>>

implements ResultServiceHolder<M, ID, BO> {

public static ResultTypes<?, ?, ?>[] values() {

return new ResultTypes<?, ?, ?>[] {RESULT_ONE, RESULT_TWO, RESULT_THREE};

}

public static final ResultTypes<ResultOne, Long, ResultOneBO> RESULT_ONE = new ResultTypes<ResultOne, Long, ResultOneBO>("Result One") {

@Override

public ResultOneService getService() {

return serviceInitializer.resultOneService;

}

};

public static final ResultTypes<ResultTwo, Long, ResultTwoBO> RESULT_TWO = new ResultTypes<ResultTwo, Long, ResultTwoBO>("Result Two") {

@Override

public ResultTwoService getService() {

return serviceInitializer.resultTwoService;

}

};

public static final ResultTypes<ResultThree, Long, ResultThreeBO> RESULT_THREE = new ResultTypes<ResultThree, Long, ResultThreeBO>("Result Three") {

@Override

public ResultThreeService getService() {

return serviceInitializer.resultThreeService;

}

};

protected String name;

protected ServiceInitializer serviceInitializer;

private ResultTypes(String name) {

this.name = name;

}

protected void setServiceInitializer(ServiceInitializer serviceInitializer) {

this.serviceInitializer = serviceInitializer;

}

@Component

static class ServiceInitializer {

@Autowired

private ResultOneService resultOneService;

@Autowired

private ResultTwoService resultTwoService;

@Autowired

private ResultThreeService resultThreeService;

@PostConstruct

public void init() {

for (ResultTypes resultType : ResultTypes.values()) {

resultType.setServiceInitializer(this);

}

}

}

}

我认为,由于解决方案需要花费多长时间,因此我会坚持使用这种enum方法,并接受这种局限性。由于不得不添加自己的values()实现,因此我付出的努力比实施这些限制所带来的损失还要多。但是,这是一个有趣的理论练习,再次感谢你的帮助。

回答:

好吧,首先,你需要了解为什么你所做的可能不是你认为的所做的。让我们来看一个简单的例子。

interface Face {

<T> List<T> get();

}

你所拥有的是通用方法get。泛型方法的类型参数取决于调用站点提供的内容。因此,例如:

Face f = ...;

// this call site dictates T to be Number

List<Number> l = f.<Number>get();

当你覆盖它像

class Impl implements Face {

@Override

public List<String> get() { return ...; }

}

你可以执行此操作(仅由于擦除操作),但你可能不应该这样做。仅允许向后兼容非通用代码。你应该听警告并且不要这样做。这样做意味着例如,我仍然可以指示它返回其他内容:

Face f = new Impl();

// now I've caused heap pollution because you

// actually returned to me a List<String>

List<Number> l = f.<Number>get();

这就是为什么存在未经检查的转换的原因。

你可能要使用的是通用接口声明:

interface Face<T> {

List<T> get();

}

现在,参数toT取决于对象引用的类型。

Face<Number> f = ...;

// get must return List<Number>

List<Number> l = f.get();

我们可以像

class Impl implements Face<String> {

@Override

public List<String> get() { return ...; }

}

此外,你无法访问枚举上的协变返回类型。当你覆盖枚举常量上的方法时,其类为匿名。匿名类没有名称,因此无法引用。因此,程序员无法知道其协变返回类型来使用它。此外,枚举不能声明泛型类型参数。因此,使用枚举根本无法实现你想做的事情。

你可以使用带有public static final实例的类来模拟通用枚举:

public abstract class SimEnum<T> implements Face<T> {

public static final SimEnum<Number> A = new SimEnum<Number>() {

@Override

public List<Number> get() { return ...; }

};

public static final SimEnum<String> B = new SimEnum<String>() {

@Override

public List<String> get() { return ...; }

};

private SimEnum() {}

public static SumEnum<?>[] values() {

return new SimEnum<?>[] { A, B };

}

}

否则,你需要彻底改变你的想法。

以上是 Java泛型和枚举,模板参数丢失 的全部内容, 来源链接: utcz.com/qa/415664.html

回到顶部