A <T extends B>和A <?有什么区别?延伸B>?

arp*_*oid 17 java generics

我是一名新的java学习者.最近我正在阅读Generic编程,让我对此感到困惑......

A<T extends B> and A<? extends B>
Run Code Online (Sandbox Code Playgroud)

axt*_*avt 18

首先,这些是在不同环境中使用的完全不同的结构.

A<T extends B> 是泛型类型声明的一部分,如

public class A<T extends B> { ... }
Run Code Online (Sandbox Code Playgroud)

它声明了A带有类型参数的泛型类型T,并引入了一个绑定T,因此它T必须是一个子类型B.


A<? extends B> 是带有通配符的参数化类型,它可以在变量和方法声明等中使用,作为普通类型:

A<? extends B> a = ...;

public void foo(A<? extends B> a) { ... }
Run Code Online (Sandbox Code Playgroud)

变量声明如A<? extends B> a指型的aA与一些亚型参数B.

例如,鉴于此声明

List<? extends Number> l;
Run Code Online (Sandbox Code Playgroud)

您可以:

但是,您不能将任何内容放入列表中,l因为您不知道列表的实际类型参数:

Double d = ...;
l.add(d); // Won't compile
Run Code Online (Sandbox Code Playgroud)


krt*_*tek 8

?就是所谓的通配符.这意味着任何延伸B.

当你写作时List<T extends String>,你的Listcan只包含类型的元素T.

当你写作时List<? extends String>,你的List可以包含任何元素extends String

我希望我很清楚,因为这些概念很复杂.


Yis*_*hai 5

一般而言,泛型是一个复杂的主题,尤其是在 Java 中。但基本上区别在于:

T 扩展 B

有一个特定的类型 T,它只限于是 B 或 B 的子类,但它是一个特定的已知类型。任何简单的旧泛型声明就像在说:<T extends Object>通过说 T 扩展 B,我们是说 T 比任何对象都更受限制,它必须特别是 B 的一种类型。

? 扩展 B

这意味着泛型类型是未知的,确切地说,但我们可以说它扩展了 B。它可能是 B,它可能是 B 的子类。使用通配符和字扩展,这意味着你可以从对象中取出 B,但不能以类型安全的方式在对象中放入任何东西。(?super B 的意思正好相反——你可以把一些东西放在一个 B 或 B 的超类的方法参数中,但你不能确定一个方法的返回值是什么。)


irr*_*ble 5

(长评,不是答案)

完全不同的东西.语法的相似性是Java造成的严重错误.而这个错误会导致更大的错误 - 许多人试图将通配符理解为类型参数(即通配符捕获)

A<? extends B>直到Java发明它之前没有这样的事情.在此之前,研究人员使用的语法是A<B+>.Java认为这对我们糟糕的程序员来说太神秘了,所以它发明了A<? extends B>第一轮看起来更好看的语法.

嗯,这是多么冗长和丑陋.如果API有一些通配符,它​​看起来像符号的呕吐物.

但最糟糕的是它引起的混乱.它看起来像一个类型参数.Java是故意这样做的!Java并不相信它的程序员可以理解协变类型,所以语法上它使得可变类型看起来像参数化类型,引导程序员进入错误的理解方式,不可否认,这在某些场合很有用,但最终会让人无能为力.