首页 > 解决方案 > 为什么通配符类型参数不在自引用类型的包装器范围内

问题描述

我有一个接口,其中包含返回或需要实现类型实例的方法。为此,我创建了一个表单类型变量U extends I<U>以用作返回类型。目的当然U是实现类:

interface SelfReferringInterface<U extends SelfReferringInterface<U>> {
}

现在我有一个包含不相关类型变量的实现类:

class RestrictingType<T> implements SelfReferringInterface<RestrictingType<T>> {

}

还有一个围绕 a 实例的类SelfReferringInterface

class Wrapper<T extends SelfReferringInterface<T>> {
}

Wrapper不知何故,对于采用以下通配符实例的类型,我得到一个类型推断错误RestrictingType

public class Main {

        public static void main(String... args) {
                // This type checks
                SelfReferringInterface<?> test1;
                // This too
                RestrictingType<?> test2;
                // And this
                Wrapper<RestrictingType<Object>> test3;
                // This fails
                Wrapper<RestrictingType<?>> test4;
                // Interestingly this does succeed
                Wrapper<? extends RestrictingType<?>> test5;
        }
}

编译它会产生以下错误:

Main.java:23: error: type argument RestrictingType<?> is not within bounds of type-variable T
                Wrapper<RestrictingType<?>> test4;
                                       ^
  where T is a type-variable:
    T extends SelfReferringInterface<T> declared in class Wrapper
1 error

为什么RestrictingType<?>不在范围之内T?为什么功能相似? extends RestrictingType<?>没有问题?

标签: javagenerics

解决方案


Wrapper<RestrictingType<T>>适用于任何给定类型T,因为我们知道Restricting<T>implements SelfReferringInterface<RestrictingType<T>>。但是,Wrapper<RestrictingType<?>>不起作用,因为Restricting<? #1>可能无法实现SelfReferringInterface<RestrictingType<? #2>>。通配符?表示未知类型,在这两个地方可能是两种不同的未知类型

这是了解为什么必须这样的另一种方法:假设您的Wrapper<T>类可以包含包装类型的多个项目T。那么 bound<T extends SelfReferringInterface<T>>意味着任何一项的类型都应该实现SelfReferringInterface<type of any other item>,就像 howclass SortedList<T extends Comparable<T>>意味着列表中的任何一项都应该与列表中的任何其他项进行比较。但是,如果您有Wrapper<RestrictingType<?>>,您将能够将RestrictingType<String>RestrictingType<Integer>项目添加到其中,因为这两种类型都是 的子类型RestrictingType<?>。但是,RestrictingType<String>不执行SelfReferringInterface<RestrictingType<Integer>>,因此合同被打破。

至于为什么Wrapper<? extends RestrictingType<?>>有效,我不太确定,但? extends通配符意味着你不能在其中添加任何项目,所以你不能用它来破坏合同。


推荐阅读