Java 告诉编译器<;对象>;相当于<&燃气轮机;它想要

Java 告诉编译器<;对象>;相当于<&燃气轮机;它想要,java,generics,java-8,type-conversion,wildcard,Java,Generics,Java 8,Type Conversion,Wildcard,我有一些对象预先生成一些配置一次,这样它们以后可以更快地(可能几次)处理计算。我试图将其泛化,以避免将配置作为对象传递,并每次强制转换它 interface IComputable<T> { T configure(); // Generate configuration object int compute(T conf); // Run the computation based on the pre-generated configuration flo

我有一些对象预先生成一些配置一次,这样它们以后可以更快地(可能几次)处理计算。我试图将其泛化,以避免将配置作为
对象传递,并每次强制转换它

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
    ...
}
但这会在其他一些地方产生编译问题(主要是“原始类型”警告),我希望避免比以前的解决方法更多的问题(使用
Object
而不是
T

有没有办法做到这一点?我甚至愿意在编译器设置中将这种问题从错误变成警告,或者可能有一个额外的私有方法,在单个对象中同时返回
config
result

编辑:如果我将
ComputableInfo
设置为generic,则添加“进一步编译问题”:我在接口中有另一个通过
ComputableInfo
调用的方法(请参见编辑):

ComputableInfo<?> info = getInfo(id);
info.computable.precision(info.config); // <<<--- (same kind of error)
ComputableInfo=getInfo(id);

info.computable.precision(info.config);// 您需要使用下限通配符。
对象
与通配符
本身不兼容

class ComputableInfo {
    IComputable<? super Object> computable;
    Object config;
    int result;

    ComputableInfo(String id) {
         computable = null;
         config = computable.configure();
         result = computable.compute(config);
    }
}

但是,通过将
整数
双精度
传递到该实例的方法中是安全的。在下面的代码段中,
computableSuperObject
引用了一个
IComputable
,它可能是以下之一:

  • i可计算
  • i可计算
由于引用可能是
i可计算的
,因此使用
对象
进行计算是非法的,只要
对象
可以是字符串

IComputable<? super Number> computableSuperNumber = ...;

Integer integer = 1;
Double d = 1d;
Number number = 1;
Object object = 1;                     // the Object can be also "string", see below
Object objectString = "string";
String string = "string";

computableSuperNumber.compute(integer);                     // ok
computableSuperNumber.compute(d);                           // ok
computableSuperNumber.compute(number);                      // ok
computableSuperNumber.compute(object);                      // doesn't compile
computableSuperNumber.compute(objectString);                // doesn't compile
computableSuperNumber.compute(string);                      // doesn't compile

IComputable从通配符类型获取对象并将其传递回同一对象是泛型类型系统的已知限制。例如,当你

List=…
您可能希望将元素从一个索引复制到另一个索引,如

Object o = list.get(0);
list.set(1, o);
但它不起作用,即使您避免使用非可表示类型的局部变量。换句话说,即使是以下内容也无法编译:

list.set(1, list.get(0));
但是,您可以添加执行该操作的通用帮助器方法,方法是允许在操作期间在类型参数中捕获通配符类型:

static void copyFromTo(列表l,int-from,int-to){
l、 设置(到,l.get(从));
}
List=…
copyFromTo(列表,0,1);//现在起作用了

您也可以将此模式应用于您的案例:

类可计算信息{
可计算的可计算的;
对象配置;//实际类型为
int结果;
ComputableInfo(字符串id){
computable=ComputableFactory.createFrom(id);
配置和计算(可计算);
}
私有void配置和计算(IComputable可计算){
T typedConfig=computable.configure();
this.config=typedConfig;
this.result=computeable.compute(typedConfig);
}
}
这是可行的,不需要使
ComputableInfo
generic

如果需要捕获类型的时间长于单个方法,例如,如果要多次使用创建的
config
,可以使用封装:

类可计算信息{
静态最终类CompState{
可计算的可计算的;
T配置;
CompState(可计算的c){
可计算=c;
}
私有void configure(){
config=computable.configure();
}
私有int compute(){
返回computeable.compute(配置);
}
}
CompState;
int结果;
ComputableInfo(字符串id){
state=newcompstate(ComputableFactory.createFrom(id));
state.configure();
结果=state.compute();
}
}

这样,您仍然可以避免将类型参数导出到
ComputableInfo

的用户,使
ComputableInfo
类型成为泛型是正确的解决方案。修复其他警告。出现编译错误的原因是,
IComputable
是一个包含未知类型的
IComputable
,并且您无法向其传递任意的
对象,因为编译器无法检查该对象的类型是否正确。与您无法添加到
列表
的原因相同,该列表已被多次询问和回答。您可以将您的
IComputable
强制转换为
IComputable
,但这是一个丑陋的、类型不安全的黑客行为。@chrylis小心地选择了Optimistic-我编辑了进一步的解释:我得到的“原始类型”警告可以通过使用
参数化来删除,这样会删除类型并创建错误而不是警告。我仍在调查这条路线,尽管…@Jesper确实我理解编译器为什么抱怨它。我已经详细介绍了创建可计算表、删除参数化的工厂……关于
icomputable如何感谢您的解释。但是,在第一个示例中,您声明
computableSuperNumber=computableInteger
不编译,但
computableSuperNumber=computableObject
编译。这不是另一种方式吗?代码段是正确的(试着自己编译)。下界/上界通配符的概念乍看起来很混乱,需要一段时间才能理解<代码>IComputableOK,谢谢。在它进来之前,我需要把它绕在头上一会儿;)当你有一个
IComputable时,我最终使用了
状态
类“技巧”:实际上,如果
对可计算性有意义,我们需要将逻辑移到泛型中。@Holger。。。或者使用原始类型,如
Collections::reverse
does,这很难看,imho。@Eugene
Collections::swap
是我的想法;我只是为了这个答案简化了它。这两种方法甚至都包含一条注释(在OpenJDK版本中),提到“补充私有
IComputable<? super Number> computableSuperNumber = ...;

Integer integer = 1;
Double d = 1d;
Number number = 1;
Object object = 1;                     // the Object can be also "string", see below
Object objectString = "string";
String string = "string";

computableSuperNumber.compute(integer);                     // ok
computableSuperNumber.compute(d);                           // ok
computableSuperNumber.compute(number);                      // ok
computableSuperNumber.compute(object);                      // doesn't compile
computableSuperNumber.compute(objectString);                // doesn't compile
computableSuperNumber.compute(string);                      // doesn't compile
Object o = list.get(0);
list.set(1, o);
list.set(1, list.get(0));