Java 通配符与类型参数

标签 java generics

为什么 1 有效而 2 无效?

1:

public List<? extends Integer> l1;
public List<? extends Number> l2 = l1;

2:

public List<U> l1;
public List<S> l2 = l1;
//where U and S have been previously defined as: **S extends Number,U extends Integer**

最佳答案

Generics are not covariant .例如:

List<Integer> l1;
List<Number> l2;
l1 = l2; // incompatible types
l2 = l1; // also incompatible

但是,通配符类型提供了一种表达协变的方法:

List<? extends Integer> l1;
List<? extends Number> l2 = l1; //legal

l1 被表示为 某种未知类型List,它是或扩展 Integer。类似地,l2 是某种类型的 List,它是或扩展了 Number。由于 Integer 扩展了 Number,编译器知道将 l1 分配给 l2 一定没问题。

这种情况不同:

<S extends Number, U extends Integer> void someMethod() {

    List<U> l1;
    List<S> l2 = l1; //incompatible types
}

SU 是类型参数,这意味着它们由 someMethod(或类型推断)的调用者提供一些特定类型参数。这些类型参数可以是具体类型,如 Integer 或通配符捕获。

虽然它们也是有界的,但这与使用上面的有界通配符不同。类型参数在声明时有界——在方法体内它们被理解为不会改变。例如,假设 SU 通过调用解析为 Integer:

this.<Integer, Integer>someMethod();

在这种情况下,我们可以想象方法体看起来像这样:

List<Integer> l1;
List<Integer> l2 = l1; // okay why not?

这是合法的,但我们只是碰巧走运。有很多情况是不会的。例如:

this.<Double, Integer>someMethod();

现在我们重新构想方法体:

List<Integer> l1;
List<Double> l2 = l1; // danger!

因此您可以看到有界类型参数与有界通配符有很大不同,后者允许不同的泛型类型协变地“交换”:

List<Integer> l1;
List<Double> l2;
List<? extends Number> l3;
l3 = l1;
l3 = l2;

关于Java 通配符与类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15784344/

相关文章:

java - Quarkus 使用 -Dnative-image.docker-build=true 构建 native 可执行文件 NoSuchFileException

generics - 复制 Kotlin 数组减去特定索引处的元素

c# - 将字典值转换为数组

java - 解码正则表达式

java - Quickfix 对 fpml 的支持

java - 将 Cofoja 与 Wicket 一起使用(甚至仅与 Maven 一起使用)

java - 我是否以错误的方式看待多线程? ( java )

arrays - 采用数组和字典的协议(protocol)

c# - 使用反射将项目添加到通用列表/集合

java通用通配符