我的结构相当复杂,无法正常工作。这是我所做的:
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>,但最后,它变为Object和Serializable。
BaseRepository<Object, Serializable>
BaseRepository<ResultTypeOne, Long>
resultTypeHolder.getService()
ResultService<M, ID, BO>
Object
Serializable
我究竟做错了什么?如何保留通用参数类型?
我要补充一点,是的,我确实意识到问题出在未经检查的转换问题上。但是服务定义为
public interface ResultTypeOneService extends ResultService<ResultTypeOne, Long, ResultTypeOneBO> { }
而且我不知道为什么不能推断类型。
编辑:从技术上讲,如果我明确推断出它们,则可以使用:
ResultTypes.RESULT_TYPE_ONE.<ResultTypeOne, Long, ResultTypeOneBO>getService().getRepository()
但是它应该是自动的,为什么它不能自动工作?我应该为它提供某种包含该类型的对象吗?为什么返回类型还不够呢?
EDIT2:的超类ResultTypeOne是
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()实现,因此我付出的努力比实施这些限制所带来的损失还要多。但是,这是一个有趣的理论练习,再次感谢你的帮助。
values()
好吧,首先,你需要了解为什么你所做的可能不是你认为的所做的。让我们来看一个简单的例子。
interface Face { <T> List<T> get(); }
你所拥有的是通用方法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(); }
现在,参数to T取决于对象引用的类型。
to
T
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 }; } }
否则,你需要彻底改变你的想法。