泛型.使用通配符`<?>`vs使用类型参数`<E>`

use*_*911 3 java generics wildcard

所以我通过官方的java教程,https://docs.oracle.com/javase/tutorial/java/generics/index.html,也通过stackoverflow搜索,结果发现使用<E>和之间没有太大的区别<?>,一个我可以理解的是普通的通用形式,另一个是通配符.到目前为止,我遇到的唯一区别是,当使用<E><E extetnds BlaBlaClass>我们可以引用类型时E,否则我们根本不知道有关集合或数组或类型的任何信息.

我的问题是:使用<?>(通配符)优于普通泛型是否有任何优势<E>?如果是这样,这种情况的情况是什么?为什么有人会使用通配符呢?

我看过泛型类型和通配符类型之间的区别,区别?(通配符)和Java中的Type参数,何时使用泛型方法以及何时使用通配符?,Java泛型?,E和T有什么区别?.到目前为止,它似乎<?>是较差的版本<E>

Sea*_*der 6

无限通配符?在通用类型无关紧要的情况下非常有用.假设您有一个检查列表大小的方法,如果它太大,则清除它,并且您希望它接受包含任何类型元素的列表:

public static <E> void checkList(List<E> list, int max) {
    if (list.size() > max) list.clear();
}
Run Code Online (Sandbox Code Playgroud)

您声明了类型变量E,但是size()clear()方法不需要它,因此它未被使用.相反,你可以这样做:

public static void checkList(List<?> list, int max) {
    if (list.size() > max) list.clear();
}
Run Code Online (Sandbox Code Playgroud)

这简化了方法声明,并使其他程序员明白此方法与列表元素的类型无关.


无界通配符也可用于字段或局部变量声明(其中不能声明类型变量),以允许使用任何泛型类型赋值.

public static void main(String[] args) {
    List<?> list;
    list = new ArrayList<Object>();
    list = new ArrayList<String>();
    list = new ArrayList<Integer>();
}
Run Code Online (Sandbox Code Playgroud)

如果是这样List<Object>,最后两行将无法编译.它可能是<? extends Object>,但这相当于<?>.

对于更实际的示例,假设您想要一个值可以是任何列表的映射:

public class MyClass {
    public final Map<String, List<?>> lists = new HashMap<>();
}
Run Code Online (Sandbox Code Playgroud)

最后,如果您需要将值转换为泛型类,并且您不确定其类型参数,则必须使用?它们.(从不使用原始类型,它会禁用泛型类型的安全检查.)一个很好的例子就是常见的equals()实现:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    MyClass<?> other = (MyClass<?>) obj;
    if (!myField.equals(other.myField)) return false;
    return true;
}
Run Code Online (Sandbox Code Playgroud)

有关Java泛型的更多信息,请查看Angelika Langer的泛型常见问题解答.


ysh*_*vit 3

假设您正在使用某个 Foo 类的实例。

  • 如果您有 Foo,则可以将其添加到 a List<Foo>orList<? super Foo>但不能添加到 a List<?>or List<? extends Foo>
  • 如果你想要一个 Foo,你可以从 a List<Foo>or获取它List<? extends Foo>,但不能从List<?>orList<? super Foo>获取它(它将返回为 Object)

所以,这就是优点:您可以根据列表的 Foo 元素与列表进行交互。

如果您关心的是 List 是否为空,或者其他不依赖于其元素的特定形状的东西,那么 aList<?>就可以了。

这同样适用于您使用泛型方法并且正在处理泛型实例E而不是特定类 Foo 的情况:

public <E> void addIfEmpty(E element) {
    List<? super E> listOfE = ...; // or List<E>
    if (!listOfE.isEmpty()) {
        listOfE.add(element);
    }

    List<?> listOfWild = ...;
    if (!listOfWild.isEmpty()) {
        listOfWild.add(element); // compilation error
    }
}
Run Code Online (Sandbox Code Playgroud)