Java中未绑定通配符泛型的用途和意义是什么?

Java中未绑定通配符泛型的用途和意义是什么?,java,generics,wildcard,Java,Generics,Wildcard,我不明白非绑定通配符泛型有什么用。当您的方法并不真正关心实际类型时,具有上限未绑定类型的绑定通配符泛型非常有用 一个简单的例子是: public void printStuff(Iterable<?> stuff) { for (Object item : stuff) { System.out.println(item); } } 如果不使用类型参数(即使用原始类型),则可以向集合中添加任何内容: Collection c = new ArrayList<S

我不明白非绑定通配符泛型有什么用。当您的方法并不真正关心实际类型时,具有上限
未绑定类型的绑定通配符泛型非常有用

一个简单的例子是:

public void printStuff(Iterable<?> stuff) {
  for (Object item : stuff) {
    System.out.println(item);
  }
}
如果不使用类型参数(即使用原始类型),则可以向集合中添加任何内容:

Collection c = new ArrayList<String>();
c.add("foo");
c.add(new Integer(300));
c.add(new Object());
Collection c=newarraylist();
c、 添加(“foo”);
c、 加(新整数(300));
c、 添加(新对象());

请注意,编译器会警告您不要使用原始类型,特别是出于这个原因:它会删除与泛型相关的任何类型检查。

当您的方法并不真正关心实际类型时,未绑定类型可能会很有用

一个简单的例子是:

public void printStuff(Iterable<?> stuff) {
  for (Object item : stuff) {
    System.out.println(item);
  }
}
如果不使用类型参数(即使用原始类型),则可以向集合中添加任何内容:

Collection c = new ArrayList<String>();
c.add("foo");
c.add(new Integer(300));
c.add(new Object());
Collection c=newarraylist();
c、 添加(“foo”);
c、 加(新整数(300));
c、 添加(新对象());

请注意,编译器会警告您不要使用原始类型,特别是出于这个原因:它会删除任何与泛型相关的类型检查。

而使用原始类型意味着您不了解泛型(因为您很懒,或者代码是很久以前编写的),使用
意味着您了解泛型,并明确强调您的代码可以处理任何类型的对象。

而使用原始类型意味着您不了解泛型(因为您懒惰或代码是很久以前编写的),使用
意味着您了解泛型,并明确强调您的代码可以处理任何类型的对象。

使用无界通配符只有在包装不使用泛型的旧代码时才有意义,基本上是集合

如果你看看你能用这样一个通用的工具做些什么,它基本上什么都不是。 如果你有一个集合,你不能添加任何东西,如果你试图读出一些东西,你总会得到一个
对象
,依此类推

这反过来有助于确保以类型安全的方式处理数据,而使用原始类型会导致编译器忽略您所造成的任何混乱


from可能会引起兴趣。

在包装不使用泛型的旧代码(基本上是集合)时,使用无界通配符才有意义

如果你看看你能用这样一个通用的工具做些什么,它基本上什么都不是。 如果你有一个集合,你不能添加任何东西,如果你试图读出一些东西,你总会得到一个
对象
,依此类推

这反过来有助于确保以类型安全的方式处理数据,而使用原始类型会导致编译器忽略您所造成的任何混乱


当您需要执行
instanceof
检查时,可能会感兴趣。

不能像这样参数化:

Object value;
if (value instanceof List<String>) {
    // ...
}
对象值;
if(列表的值实例){
// ...
}
所以你会:

Object value;
if (value instanceof List<?>) {
    // ...
}
对象值;
if(列表的值实例){
// ...
}

当您需要执行
instanceof
检查时

不能像这样参数化:

Object value;
if (value instanceof List<String>) {
    // ...
}
对象值;
if(列表的值实例){
// ...
}
所以你会:

Object value;
if (value instanceof List<?>) {
    // ...
}
对象值;
if(列表的值实例){
// ...
}
对于未绑定通配符,存在(很少)完全正确的用例。SDK包含其中的一些

一个例子是一个方法,它对任何类型的列表执行确定操作,并且在
集合中不返回任何作为
旋转的

static void rotate(List<?> list, int distance)
静态空心旋转(列表,整数距离)
另一个示例是,当您想列出类的可能构造函数时,方法是:

Constructor<?>[] getConstructors()
Constructor[]getConstructors()
这里甚至不可能使用泛型,因为根据定义,数组将包含不同的构造函数,每个构造函数都有自己的实际类。相比之下,API使用通用签名来获取单个构造函数:
constructor getConstructor(Class…parameterTypes)

结论是,即使它主要用于与旧代码的兼容性,仍然有一些地方未绑定的通配符泛型是正确的方法。

有(很少)完全正确的未绑定通配符用例。SDK包含其中的一些

一个例子是一个方法,它对任何类型的列表执行确定操作,并且在
集合中不返回任何作为
旋转的

static void rotate(List<?> list, int distance)
静态空心旋转(列表,整数距离)
另一个示例是,当您想列出类的可能构造函数时,方法是:

Constructor<?>[] getConstructors()
Constructor[]getConstructors()
这里甚至不可能使用泛型,因为根据定义,数组将包含不同的构造函数,每个构造函数都有自己的实际类。相比之下,API使用通用签名来获取单个构造函数:
constructor getConstructor(Class…parameterTypes)


结论是,即使它主要用于与旧代码的兼容性,仍然有一些地方使用未绑定的通配符泛型是正确的方法。

请允许我重新表述这个问题:

“列表
和列表
之间有什么区别?”

答案是
列表
更具限制性。它告诉我们,我们有一堆某种类型的对象,但这种类型不一定是
对象

因为我们不知道该类型是什么,所以根本无法添加到列表中-我们添加的任何内容都可能是错误的类型。事实上,我们不能将任何
类型的参数传递给任何方法,而不仅仅是
add()

另一方面,当我们指定一个方法采用
List
时,它可以采用
List
List
或任何其他
List
<代码>列表
只能获取
列表