泛型:为什么在方法参数传递中允许使用通配符和反之亦然?

时间:2016-10-25 09:31:18

标签: java list generics jvm object-reference

我有以下代码:

public static void swap(List<?> list) {
    swapHelper(list); //1
}

private static <E> void swapHelper(List<E> list) {
    swap(list); //2
}

{
    List<?> tW = new ArrayList<>();
    List<E> tE = new ArrayList<>();

    tW = tE; // 3
    tE = tW; // 4
}

在此代码行1和2中成功编译,并不意味着: 我可以将List<?>的引用分配给List<E>的引用,反之亦然? 如果是这样,那么为什么第4行不能编译。

1 个答案:

答案 0 :(得分:-2)

<?><E>都是未知类型;但是所有List<?>都有某些类型的元素,因此您可以调用参数为List<E>的方法,因为有一些未知类型与之匹配。

请注意,您无法执行此操作:

public static void swap(Object object, List<?> list) {
    swapHelper(object, list); // Compiler error: object not in bounds of list.
}

private static <E> void swapHelper(E object, List<E> list) {
    swap(object, list); // OK.
}

因为您现在不知道Object是否在List<?>的范围内。

您也不能在列表中添加新的非空值:

private static <E> void swapHelper(List<E> list) {
    list.add(new E());  // Can't create an instance of type variable.
    swap(list);
}

但您可以添加从列表中获取的值,因为它们已知在列表的范围内:

private static <E> void swapHelper(List<E> list) {
    list.add(list.get(0));
    swap(list);
}

所以从swapHelper调用原始swap是安全的类型,因为你不能导致某些东西不能转换为E(无论那种类型是什么)列表。

tWtE类似:

  • 如果您指定tW = tE,则无法向tW以外的null添加任何内容,因此您无法将tE置于包含任何内容的状态除了E
  • 的实例
  • 如果您被允许分配tE = tW,则可以E的非空实例添加到tE。这可能意味着您可以将错误类的实例添加到tW,这可能会导致运行时类型错误。因此,这项任务是被禁止的。

请注意,分配列表不会导致列表被复制:如果您分配tE = tW,然后tE == tW,那么应用于tE的所有更改也会通过{{tW显示1}},因为它们是同一个实例。