我有一个实现通用接口的通用类型。 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。这就是为什么有编译警告的原因。

10-06 05:29
查看更多