繁体   English   中英

泛型,类型参数和通配符

[英]Generics, Type Parameters and Wildcards

我试图理解java泛型,它们似乎非常难以理解。 例如,这很好......

public class Main {

    public static void main(String[] args) {
        List<?> list = null;
        method(list);
    }

    public static <T> void method(List<T> list) { }
}

......这就是......

public class Main {

    public static void main(String[] args) {
        List<List<?>> list = null;
        method(list);
    }

    public static <T> void method(List<T> list) { }
}

... 还有这个 ...

public class Main {

    public static void main(String[] args) {
        List<List<List<?>>> list = null;
        method(list);
    }

    public static <T> void method(List<List<T>> list) { }
}

...但这不编译:

public class Main {

    public static void main(String[] args) {
        List<List<?>> list = null;
        method(list);
    }

    public static <T> void method(List<List<T>> list) { }
}

有人可以用简单的语言解释发生了什么吗?

通用类型要理解的主要问题是它们不是协变的。

所以你可以这样做:

final String string = "string";
final Object object = string;

以下内容无法编译:

final List<String> strings = ...
final List<Object> objects = strings;

这是为了避免您绕过泛型类型的情况:

final List<String> strings = ...
final List<Object> objects = strings;
objects.add(1);
final String string = strings.get(0); <-- oops

所以,逐个浏览你的例子

1

你的泛型方法采用List<T> ,你传入一个List<?> ; 它(基本上)是一个List<Object> 可以将T分配给Object类型,编译器也很满意。

2

您的通用方法是相同的,您传入List<List<?>> T可以分配给List<?>类型,编译器也很高兴。

3

这与另一个嵌套级别的2基本相同。 T仍然是List<?>类型。

4

这里是一个小梨形的地方,我从上面的点进来。

您的泛型方法采用List<List<T>> 您传入List<List<?>> 现在,由于泛型类型不协变,因此无法将List<?>分配给List<T>

实际的编译器错误(Java 8)是:

required: java.util.List<java.util.List<T>> found: java.util.List<java.util.List<?>> reason:无法推断类型变量T (参数不匹配; java.util.List<java.util.List<?>>无法转换为java.util.List<java.util.List<T>>

基本上编译器告诉你它找不到要分配的T ,因为必须推断嵌套在外部列表中的List<T>的类型。

让我们更详细地看一下这个:

List<?>是一个未知类型List - 它可以是List<Integer>List<String> ; 我们可以从它get Object但我们无法add 因为否则我们遇到了我提到的协方差问题。

List<List<?>>是一个ListList一些未知类型的-它可能是一个List<List<Integer>>List<List<String>> 在案例1中 ,可以将T分配给Object ,而不允许在通配符列表上add操作。 在案例4中,这不可能完成 - 主要是因为没有一个泛型构造来阻止add到外部List

如果编译器在第二种情况下将T分配给Object ,则可能出现以下内容:

final List<List<Integer>> list = ...
final List<List<?>> wildcard = list;
wildcard.add(Arrays.asList("oops"));

因此,由于协方差,无法安全地将List<List<Integer>>分配给任何其他通用List

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM