如何解决告诉编译器<Object>等同于它想要的<?>
我有一些对象会预先生成一些配置,因此它们以后可以更快地处理计算(可能是几次)。我正在尝试对其进行通用化,以避免将配置作为Object
传递并每次进行转换。
interface IComputable<T> {
T configure(); // Generate configuration object
int compute(T conf); // Run the computation based on the pre-generated configuration
float precision(T conf); // Make the compute() computation finer-grained
...
}
class ComputableInfo {
IComputable<?> computable;
Object config; // Real type is <?>
int result;
ComputableInfo(String id) {
computable = ComputableFactory.createFrom(id);
config = computable.configure();
result = computable.compute(config); // <<<--- The method compute(capture#3-of ?) in the type TestInterface.IComputable<capture#3-of ?> is not applicable for the arguments (Object)
}
}
我遇到编译错误:
类型为TestInterface.IComputable
的方法compute(capture#3-of?)不适用于参数(Object)
当然,我可以将int compute(T conf)
替换为int compute(Object conf)
,但必须将其显式转换为适当的T
。这不是什么大问题,但是它使代码不那么明显。
我也可以使用{p>
ComputableInfo
但这会在其他一些地方引起编译问题(主要是“原始类型”警告),我希望避免使用比以前的解决方法更多的方法(使用interface ComputableInfo<T> {
IComputable<T> computable;
T config;
...
而不是Object
)。 / p>
有没有办法做到这一点?我什至愿意在编译器设置中将此类问题从错误转变为警告,或者有一个额外的私有方法可以在单个对象中同时返回T
和config
?
编辑:如果我将result
设为泛型,则将“进一步的编译问题”加起来:接口中有另一种方法,通过ComputableInfo
来调用(参见编辑):
ComputableInfo
问题是ComputableInfo<?> info = getInfo(id);
info.computable.precision(info.config); // <<<--- (same kind of error)
无法知道ComputableInfo
的{{1}}类型(或者我无法知道),因为它来自工厂,工厂是通过配置文件。
解决方法
从通配类型获取对象并将其传递回同一对象是通用类型系统的已知限制。例如,当您拥有
List<?> list = …
您可能希望将元素从一个索引复制到另一个索引,例如
Object o = list.get(0);
list.set(1,o);
,但即使您避免使用不可表示类型的局部变量,它也无法正常工作。换句话说,即使以下内容也无法编译:
list.set(1,list.get(0));
但是您可以添加一个通用的辅助方法来执行该操作,方法是允许在操作期间捕获类型参数中的通配符类型:
static <T> void copyFromTo(List<T> l,int from,int to) {
l.set(to,l.get(from));
}
List<?> list = …
copyFromTo(list,1); // now works
您也可以将此模式应用于您的案例:
class ComputableInfo {
IComputable<?> computable;
Object config; // Real type is <?>
int result;
ComputableInfo(String id) {
computable = ComputableFactory.createFrom(id);
configureAndCompute(computable);
}
private <T> void configureAndCompute(IComputable<T> computable) {
T typedConfig = computable.configure();
this.config = typedConfig;
this.result = computable.compute(typedConfig);
}
}
这有效,不需要将ComputableInfo
设为通用。
如果您需要捕获类型的时间长于单个方法,例如如果要多次使用创建的config
,可以使用封装:
class ComputableInfo {
static final class CompState<T> {
IComputable<T> computable;
T config;
CompState(IComputable<T> c) {
computable = c;
}
private void configure() {
config = computable.configure();
}
private int compute() {
return computable.compute(config);
}
}
CompState<?> state;
int result;
ComputableInfo(String id) {
state = new CompState<>(ComputableFactory.createFrom(id));
state.configure();
result = state.compute();
}
}
这样,您仍然避免将类型参数导出到ComputableInfo
的用户。
您需要使用下界通配符。 Object
与通配符?
本身不兼容。
class ComputableInfo {
IComputable<? super Object> computable;
Object config;
int result;
ComputableInfo(String id) {
computable = null;
config = computable.configure();
result = computable.compute(config);
}
}
下限指出IComputable
将是Object
的实例,或者某个对象的实例是Object
的超类(实际上,该对象是所有{{ 1}})。为了更好地理解,让我们使用Objects
:
Number
但是,将IComputable<Integer> computableInteger = ...;
IComputable<Number> computableNumber = ...;
IComputable<Object> computableObject = ...;
IComputable<? super Number> computableSuperNumber = ...;
computableSuperNumber = computableInteger; // doesn't compile
computableSuperNumber = computableNumber; // ok
computableSuperNumber = computableObject; // ok
或Integer
传递到该实例的方法中是安全的。在Double
下面的代码段中引用了一个computableSuperObject
,它可能是以下其中之一:
-
IComputable
-
IComputable<Number>
。
由于引用可能为IComputable<Object>
,因此,只要IComputable<Number>
可以存在,则使用Object
进行计算是非法的。 Object
。
String
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。