为什么Java类型推断不适用于参数化类型的返回值?

时间:2019-02-22 14:21:27

标签: java generics

我有一个实现通用接口的通用类型。 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,但是不能在{{1}中设置T的类型}

当我在T getValue()中对T使用强制类型转换时,它会抱怨未检查的强制类型转换。

为什么类型推断对设置方法有用,但对getter不起作用?

1 个答案:

答案 0 :(得分:3)

T中的

Generic<T extends ISpecific>可以扩展为ISpecific 的任何类型。

这意味着它可以ISpecificImplementer,或者它可以为其他匹配类型。 T的选择不取决于决定方法。取决于创建Generic<T>实例的情况。

getValue()内部,您试图返回一个ISpecificImplementer。现在T 可能ISpecificImplementer,或者它可能是其他不兼容的类型。因此,它需要强制转换。强制转换为泛型类型会产生警告,因为它绕过了泛型打算提供的类型安全性。

假设SomeOtherType是另一个实现ISpecific的类。 如果实例化一个Generic<SomeOtherType>并调用getValue(),则将导致强制转换异常,因为getValue() 应该返回一个SomeOtherType,但是它会实际上尝试返回一个ISpecificImplementer。这就是为什么会有编译警告的原因。