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

Java泛型和枚举,模板参数丢失,java,spring,generics,enums,Java,Spring,Generics,Enums,我有一个相当复杂的结构,它没有按预期工作。这就是我所做的: public interface ResultServiceHolder { <M, ID extends Serializable, BO extends BusinessObject<M, ID>> ResultService<M, ID, BO> getService(); } public enum ResultTypes implements ResultServiceHolder

我有一个相当复杂的结构,它没有按预期工作。这就是我所做的:

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
    }
}
这是很好的工作和花花公子。然而,如果我说

ResultTypes.RESULT_TYPE_ONE.getService().getRepository()
然后它是
BaseRepository
,而不是
BaseRepository
。方法
resultTypeHolder.getService()
返回
ResultService
,但最终,它变成了
对象
可序列化

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

我想补充一点,是的,我确实意识到问题在于未经检查的铸造。但这些服务被定义为

public interface ResultTypeOneService
    extends ResultService<ResultTypeOne, Long, ResultTypeOneBO> {
}
但它不会映射到边界中的任何位置

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);
            }
        }
    }
}
公共接口结果服务持有者{
ResultService getService();
}
公共抽象类结果类型
实现ResultServiceHolder{
公共静态结果类型[]值(){
返回新的结果类型[]{RESULT\u ONE、RESULT\u TWO、RESULT\u THREE};
}
公共静态最终结果类型RESULT\u ONE=新结果类型(“结果一”){
@凌驾
公共结果服务getService(){
返回serviceInitializer.resultOneService;
}
};
公共静态最终结果类型RESULT\u TWO=新结果类型(“结果二”){
@凌驾
public ResultTwoService getService(){
返回serviceInitializer.resultTwoService;
}
};
公共静态最终结果类型RESULT\u THREE=新结果类型(“结果三”){
@凌驾
public ResultThreeService getService(){
返回serviceInitializer.ResultThreservice;
}
};
受保护的字符串名称;
受保护的ServiceInitializer ServiceInitializer;
私有结果类型(字符串名称){
this.name=名称;
}
受保护的无效设置ServiceInitializer(ServiceInitializer ServiceInitializer){
this.serviceInitializer=serviceInitializer;
}
@组成部分
静态类服务初始值设定项{
@自动连线
私有ResultOneService ResultOneService;
@自动连线
私有ResultTwoService ResultTwoService;
@自动连线
私有结果三项服务结果三项服务;
@施工后
公共void init(){
对于(ResultTypes resultType:ResultTypes.values()){
resultType.setServiceInitializer(this);
}
}
}
}

我认为,由于解决方案变得如此冗长,我将坚持使用
enum
方法,并接受这种边界损失。我必须添加自己的
values()
实现,这比强制执行这些边界所获得的更多。然而,这是一个有趣的理论练习,再次感谢你的帮助。

你不能做你想做的事

List
List
运行时的面类型擦除

枚举映射的
getService()
函数也是如此


与泛型类型相关的所有内容都在编译时进行验证。

您不能做您想做的事情

List
List
运行时的面类型擦除

枚举映射的
getService()
函数也是如此


与泛型类型相关的所有内容都在编译时进行验证。

是否可以使用接口/抽象类而不是枚举

枚举不能有类型参数,但类和接口可以

例如

接口 Entity.java

“东西”界面


希望这有帮助…

是否可以使用接口/抽象类而不是枚举

枚举不能有类型参数,但类和接口可以

例如

接口 Entity.java

“东西”界面


希望这能有所帮助……

好的,首先你需要理解为什么你正在做的可能不是你认为它正在做的。让我们看一个更简单的例子

interface Face {
    <T> List<T> get();
}
当你像这样覆盖它的时候

class Impl implements Face {
    @Override
    public List<String> get() { return ...; }
}
我们可以像这样实施它

class Impl implements Face<String> {
    @Override
    public List<String> get() { return ...; }
}

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

好的,首先你需要理解为什么你正在做的可能不是你认为它正在做的。让我们看一个更简单的例子

interface Face {
    <T> List<T> get();
}
当你像这样覆盖它的时候

class Impl implements Face {
    @Override
    public List<String> get() { return ...; }
}
我们可以像这样实施它

class Impl implements Face<String> {
    @Override
    public List<String> get() { return ...; }
}


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

这不是一个典型的类型擦除问题吗?@EvanKnowles可能是,但我不希望类型被擦除。我的泛型
getService()
方法出现问题,无法解析
ResultTypeOneService
,因为
@evannowles甚至可以在调用
getService()
中保留类型参数吗?好吧,我迷路了。我不知道如何使类型工作。ResultTypeOne的超类是什么?这不只是一个典型的类型擦除问题吗?@EvanKnowles可能是,但我不希望类型被擦除。我的泛型
getService()
方法出现问题,无法解析
ResultTypeOneService
,因为
@evannowles甚至可以在调用
getService()
中保留类型参数吗?好吧,我迷路了。我不知道如何使类型工作。ResultTypeOne的超类是什么?我知道它在运行时会被删除,但从技术上讲,我的问题是
不会自动解析为
,即使我在
getService()
方法中返回的服务定义了这些参数。基本上,我是通过在编译时调用
getService()
来获取原始类型的。@EpicPandaForce这是一个如何获取原始类型的问题?我原以为它不会成为原始类型,但事实确实如此。我很想知道是否有可能以某种方式使它不是原始类型。请参阅答案。无法防止类型擦除。valida
public class Entity1 implements Entity<String> {
    // TODO implement Entity stuff...
}
public class Entity2 implements Entity<Integer> {
    // TODO implement methods...
}
public class Entity1Service implements Service<String, Entity1> {

    // Would not have to implement this if you extended an abstract base Service class
    @Override
    public Entity1 get(String key) {
        return null;
    }

}
public class Entity2Service implements Service<Integer, Entity2> {

    // Wouldn't need this if you had abstract Service class either...
    @Override
    public Entity2 get(Integer key) {
        return null;
    }

}
import java.io.Serializable;

public abstract class ServiceHolder<K extends Serializable, V, S extends Service<K, V>> {

    public static final ServiceHolder<String, Entity1, Entity1Service> ENTITY_1_SERVICE = new ServiceHolder<String, Entity1, Entity1Service>() {};
    public static final ServiceHolder<Integer, Entity2, Entity2Service> ENTITY_2_SERVICE = new ServiceHolder<Integer, Entity2, Entity2Service>() {};

    private S service;

    private ServiceHolder() {
    }

    public S getService() {
        return service;
    }

    public void setService(S service) {
        this.service = service;
    }
}
public class PleaseCompile {

    public static void main(String[] args) {
        Entity1 solid1 = ServiceHolder.ENTITY_1_SERVICE.getService().get("[KEY]");
        Entity2 solid2 = ServiceHolder.ENTITY_2_SERVICE.getService().get(42);

        ...
    }
}
interface Face {
    <T> List<T> 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();
}
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 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 };
    }
}