有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

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() {};
    }
}

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

但是如果我在extends BaseConfiguration<K,V>中删除generic,程序将被成功编译

因此,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:

问题的简单示例(从extends Base<T>中删除<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) 个答案

  1. # 1 楼答案

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

    根据Java spec

    The supertype of a class may be a raw type. Member accesses for the class are treated as normal, and member accesses for the supertype are treated as for raw types. In the constructor of the class, calls to super are treated as method calls on a raw type.

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

    public void test(ArrayList list) {}
    

    因此,不会发生编译错误

  2. # 2 楼答案

    工厂生成器似乎应该采用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的第二个实现会编译,但会出现警告,因为它使用的是原始类型