我有一个实现通用接口的通用类型。 Java编译器在所有情况下都能正确推断出类型的type参数中的约束,但无法一次推断出约束。
请参见下面的通用类中的getValue()
方法实现:
package test.gen.company;
public class GenericProblem {
Generic<ISpecific> gen = new Generic<>();
//compiler has no problems here
ISpecific val = gen.getValue();
Generic<IMoreSpecific> gen2 = new Generic<>();
//both of these are OK
ISpecific val1 = gen2.getValue();
IMoreSpecific val2 = gen2.getValue();
//compiler won't allow this,
//correctly complains irrelevant is not within bounds
//Generic<Irrelevant> gen;
}
interface IGeneric<T>{
T getValue();
void setValue(T in);
}
interface ISpecific {}
interface IMoreSpecific extends ISpecific {}
interface Irrelevant{}
class ISpecificImplementer implements ISpecific {}
class Generic<T extends ISpecific> implements IGeneric<T> {
@Override
public T getValue() {
//error: required T, found ISpecificImplementer
return new ISpecificImplementer();
//Unchecked cast
//return (T) new ISpecificImplementer();
}
@Override
public void setValue(T in) {
//no complaints here, compiler knows T is ISpecific
wantSomeB(in);
}
private void wantSomeB(ISpecific in){
if (in == null) {
throw new RuntimeException("I'm completely meaningless");
}
}
}
编译器根据
setValue(T in)
的类型参数将T extends ISpecific
中的参数类型设置为Generic
,但是不能在T
中设置T getValue()
的类型。当我在
T
中对getValue()
使用强制转换时,它会抱怨未检查的强制转换。为什么类型推断对设置方法有效,但对获取方法无效?
最佳答案
允许T
中的Generic<T extends ISpecific>
是扩展ISpecific
的任何类型。
这意味着它可以是ISpecificImplementer
,也可以是其他一些匹配类型。 T
的选择取决于决定方法。取决于创建Generic<T>
实例的方式。
在getValue()
中,您尝试返回一个ISpecificImplementer
。现在T
可能是ISpecificImplementer
,或者可能是其他不兼容的类型。因此,它需要强制转换。强制转换为泛型类型会产生警告,因为它绕过了泛型打算提供的类型安全性。
假设SomeOtherType
是另一个实现ISpecific
的类。
如果实例化Generic<SomeOtherType>
并调用getValue()
,则最终将导致强制转换异常,因为getValue()
应该返回SomeOtherType
,但实际上它将尝试返回ISpecificImplementer
。这就是为什么有编译警告的原因。