不兼容的类型:推断的类型不符合上限

时间:2018-08-07 15:13:44

标签: java generics java-8 typechecking

当我看到以下错误时,我正在实现某种体系结构:

Error:(33, 55) java: incompatible types: inferred type does not conform to upper bound(s)
    inferred: java.io.Serializable
    upper bound(s): sandbox.ExpirePolicy,java.io.Serializable

完整的简化代码如下:

interface Configuration<K,V>{}
interface ExpirePolicy{}
interface Factory<T>{}


class FactoryBuilder {
    public static <T extends Serializable> Factory<T> of(T instance){
        System.out.println(instance.getClass());
        return new Factory<T>() {};
    }
}

class BaseConfiguration<K,V> implements Configuration<K,V> {
    public BaseConfiguration<K,V> setExpiryPolicyFactory(Factory<? extends ExpirePolicy> factory){
        return this;
    }
}

class C<K,V> extends BaseConfiguration<K,V> {
    public C<K,V> setExpiration(){
        super.setExpiryPolicyFactory(FactoryBuilder.of((Serializable) getExpirePolicy()));
        return this;
    }

    private ExpirePolicy getExpirePolicy(){
        return new ExpirePolicy() {};
    }
}

例外情况是尝试使用setExpiryPolicyFactory(Factory<? extends ExpirePolicy> factory)的实例调用Factory<Serializable>

但是,如果我在extends BaseConfiguration<K,V>中删除泛型,则程序将成功编译。

因此,类C的下一个声明是正确的:

class C<K,V> extends BaseConfiguration {
    public C<K,V> setExpiration(){
        super.setExpiryPolicyFactory(FactoryBuilder.of((Serializable) getExpirePolicy()));
        return this;
    }

    private ExpirePolicy getExpirePolicy(){
        return new ExpirePolicy() {};
    }
}

问题是:为什么第二个实现(类C)将被成功编译,而第一个实现则没有成功?

UPD:

简单的问题示例(从<T>中删除extends Base<T>,程序可以很好地编译:

class Base<T> {
    public void test(ArrayList<? extends CharSequence> list) {}
}

class Derived<T> extends Base<T> {
    public void callTest() {
        super.test(new ArrayList<Integer>());
    }
}

2 个答案:

答案 0 :(得分:1)

当您从<T>语句中删除extends Base<T>时,Base类开始被视为原始类型

根据Java spec

  

类的超类型可以是原始类型。会员访问   类被视为普通类,并且对超类型的成员访问为   视为原始类型。在类的构造函数中,调用   将super视为对原始类型的方法调用。

这意味着super.test(...)调用也被视为对原始类型的方法调用,就好像它已被声明为:

public void test(ArrayList list) {}

因此不会发生编译错误。

答案 1 :(得分:0)

工厂创建者似乎应该使用ExpirePolicy而不是Serializable来创建工厂。将签名更改为

class FactoryBuilder {
    public static <T extends ExpirePolicy> Factory<T> of(T instance){
        System.out.println(instance.getClass());
        return new Factory<T>() {};
    }
}

启用

class C<K,V> extends BaseConfiguration<K,V> {

      public C<K,V> setExpiration(){
          super.setExpiryPolicyFactory(FactoryBuilder.of(getExpirePolicy()));
          return this;
      }

      private ExpirePolicy getExpirePolicy(){
          return new ExpirePolicy() {};
      }
}

无需额外强制转换。

C的第二种实现可以编译,但是带有警告,因为它使用的是原始类型。