简体   繁体   English

Java通用方法,通配符List返回类型

[英]Java generic methods, wildcard List return type

Java's 8 method signature looks as follows: Java的8种方法签名如下所示:

public static <E extends CharSequence> List<? super E> m(List<E> list);

And somewhere in code, method call: 在代码中的某个地方,方法调用:

result = m(list);

Suppose that I've create argument list as follows: 假设我已经如下创建参数list

List<String> list = new ArrayList<>();

My question is, why the result can be just raw List , and can't be even a List<Object> ? 我的问题是,为什么result只能是原始List ,甚至不能是List<Object>

Calling your method with a List<String> as an argument is like calling the following method: List<String>作为参数调用您的方法就像调用以下方法:

public static List<? super String> m(List<String> list) { ... }

Consider the following starting code: 考虑以下起始代码:

List<String> list = new ArrayList<>();
List<? super String> result = m(list);

This calls the above mentioned method and stores the return value into the variable result - which is typed exactly with the method's return type. 这将调用上述方法,并将返回值存储到变量result -该变量的值必须与方法的返回类型完全相同。

The question now is: To what variables - or better what types - can you assign this variable? 现在的问题是:可以将此变量分配给哪些变量,或者更好地分配给哪种类型? So we are speaking about assignment compatibility. 因此,我们正在谈论分配兼容性。

Consider these assignments: 考虑以下任务:

List<String> result1 = result; // compiler error: type mismatch (not assignable)
List<Object> result2 = result; // compiler error: type mismatch (not assignable)

List result3 = result; // ok
List<?> result4 = result; // ok

List<? super String> result5 = result; // ok
List<? extends Object> result6 = result; // ok

To understand the nature of this error, you must know that generics are invariant . 要了解此错误的性质,您必须知道泛型是不变的 That means, the type List<String> is not a subtype of List<Object> - although the types String and Object have such a subtype hierarchy. 这意味着,类型List<String> 不是 List<Object>的子类型-尽管类型StringObject具有此类子类型层次结构。

So, what we are trying here is: 因此,我们在这里尝试的是:

  1. Assign a List<? super String> 分配List<? super String> List<? super String> to a List<String> => fails, no subtyping List<? super String>List<String> =>失败,没有子类型
  2. Assign a List<? super String> 分配List<? super String> List<? super String> to a List<Object> => fails, no subtyping List<? super String>List<Object> =>失败,没有子类型
  3. Assign a List<? super String> 分配List<? super String> List<? super String> to a List => succeeds, because using raw types opts out from type checking generally List<? super String>List =>成功,因为使用原始类型通常会从类型检查中退出
  4. Assign a List<? super String> 分配List<? super String> List<? super String> to a List<?> => succeeds, because a List<?> is the supertype of all List<...> List<? super String>List<?> =>的操作成功,因为List<?>是所有List<...>的超类型
  5. Assign a List<? super String> 分配List<? super String> List<? super String> to a List<? super String> List<? super String>List<? super String> List<? super String> => succeeds, because ... well ... List<? super String> =>成功,因为...
  6. Assign a List<? super String> 分配List<? super String> List<? super String> to a List<? ectends Object> List<? super String>List<? ectends Object> List<? ectends Object> => succeeds, because List<? ectends Object> List<? ectends Object> =>成功,因为List<? ectends Object> List<? ectends Object> is essentially the same as List<?> . List<? ectends Object>本质上与List<?>相同。

Note, that trying to assign a List<? super String> 注意,试图分配一个List<? super String> List<? super String> to a List<? super CharSequence> List<? super String>List<? super CharSequence> List<? super CharSequence> or a List<? extends CharSequence> List<? super CharSequence>List<? extends CharSequence> List<? extends CharSequence> will also fail. List<? extends CharSequence>也会失败。 They are not in a subtype hierarchy. 它们不在子类型层次结构中。

Why is that so? 为什么会这样? The compiler cannot guarantee that the actual list was instantiated with a type that matches the constraint ? super/extends CharSequence 编译器不能保证实际的列表使用与约束匹配的类型实例化? super/extends CharSequence ? super/extends CharSequence . ? super/extends CharSequence

The reason you can't do that is because Java generics are not covariant. 之所以不能这样做,是因为Java泛型不是协变的。 That is, List<Object> is not a super-class of List<String> . 也就是说, List<Object> 不是 List<String>的超类。 The method signature of your method m would however allow returning a List<String> , and then you would have a List<Object> typed reference pointing to List<String> . 但是,方法m的方法签名将允许返回List<String> ,然后您将得到一个List<Object>类型的引用,该引用指向List<String> Since generic type information is not available at run time, this would not raise an exception immediately, but it could result in type errors in unrelated places. 由于泛型类型信息在运行时不可用,因此不会立即引发异常,但是可能会在不相关的地方导致类型错误。

For example, suppose m is implemented as follows: 例如,假设m实现如下:

private static List<CharSequence> theResult = new ArrayList<>();

public static <E extends CharSequence> List<? super E> m(List<E> list) {
    theResult.addAll(list);
    return theResult;
}

Then using your method as follows would ad a non- CharSequence object to a List<CharSequence> : 然后,使用以下方法将一个非CharSequence对象添加到List<CharSequence>

List<Object> os = m(someList);
os.add(new Object());

Luckily, the above does not compile. 幸运的是,上面没有编译。

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

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