gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 03:13:02 25 4
gpt4 key购买 nike

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

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 的父类(super class)是

@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() 损失更多实现比我从执行这些界限中获得的 yield 。然而,这是一个有趣的理论练习,再次感谢您的帮助。

最佳答案

好的,首先您需要了解为什么您正在做的事情可能与您认为的不一样。让我们看一个更简单的例子。

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)声明:

interface Face<T> {
List<T> get();
}

现在 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 };
}
}

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

关于Java 泛型和枚举,模板参数丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28234960/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com