Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
泛型方法中的Java泛型通配符捕获_Java_Generics_Wildcard - Fatal编程技术网

泛型方法中的Java泛型通配符捕获

泛型方法中的Java泛型通配符捕获,java,generics,wildcard,Java,Generics,Wildcard,我正在学习Java泛型,正在阅读Naftalin和Wadler的(非常好的)一本书,我了解到了他所说的在通用方法中捕获通配符,如Collections中的实现。相反: public static <T> void reverse(List<T> list){ List<T> temp=new ArrayList<>(list); for(int i=0;i<list.size();i++) list.set(i

我正在学习Java泛型,正在阅读Naftalin和Wadler的(非常好的)一本书,我了解到了他所说的在通用方法中捕获通配符,如Collections中的实现。相反:

public static <T> void reverse(List<T> list){
    List<T> temp=new ArrayList<>(list);
    for(int i=0;i<list.size();i++)
        list.set(i,temp.get(list.size()-1-i));
}
公共静态无效反向(列表){
列表温度=新阵列列表(列表);
for(int i=0;i列表){
2(清单);
}
公共静态作废撤销2(列表){
列表温度=新阵列列表(列表);

对于(int i=0;i,
reverse2()
中的
T
参数不推断为
?扩展对象
,并且不使用通配符
执行实例化

推理只会发生在调用
reverse2()
的方法中。例如,如果调用
Collections.emptyList()
,类型参数是什么?在该示例中,类型参数未知,但通常可以在调用站点进行推理:

List<String> empty = Collections.emptyList();
现在,调用该方法的客户端:

final class Test {

  public static void main(String... argv) {
    List<String> list = Arrays.asList("A", "B", "C");
    Reverse.reverse(list);
    System.out.println(list);
  }

}
重新运行
测试
将产生相同的结果,而不是失败

现在更改
reverse()
方法的实现,再次只重新编译
reverse
类:

static <T extends Integer> void reverse(List<T> list)
static <T extends Integer> void reverse(List<T> list) {
  List<T> tmp = new ArrayList<>(list);
  for (int i = 0; i < list.size(); ++i) {
    T el = tmp.get(list.size() - 1 - i);
    list.set(i, el);
  }
}
这是因为
T
现在实际上被引用了:

T el = tmp.get(list.size() - 1 - i);
在该赋值中,编译器将向类型参数的上限插入一个强制转换,在本例中为
Integer

T el = (Integer) tmp.get(list.size() - 1 - i);
如果类型
T
不受限制(其上限为
Object
),则不会执行强制转换,因为它永远不会失败

list
现在被传递到
reverse2()
,参数
T
被推断为
?扩展对象
,[…]

调用
reverse2
时,将通配符捕获到一个新的类型变量,该变量不再是通配符。*将
T
的类型推断为该捕获类型

类型系统确保我们只能以安全的方式使用此功能

例如,假设我们有一个接受两个列表的方法:

static void swap2(列表1、列表2){
列表温度=新的ArrayList(列表1);
清单1.clear();
列表1.addAll(列表2);
清单2.clear();
列表2.添加所有(临时);
}
如果我们尝试使用通配符捕获调用此函数:

static void swap(List<?> list1, List<?> list2) {
    swap2(list1, list2); // <- doesn't compile
}
静态无效交换(列表1、列表2){

swap2(list1,list2);//我看不出这里有什么东西在实例化
数组列表
。请将代码片段(以及需要
正确呈现的任何代码文本)用反引号(也称为反勾号
`
)。或者,您可以突出显示文本并按
{}
按钮。@rgetman done。我在调用方法时传递类型参数。我不明白如何编写方法体传递?作为类型参数。好的,我知道了,那么它是什么?我的意思是,它被推断为什么?好的,我理解一些东西,但我不能诚实地得到所有东西…我不理解它的内部工作原理泛型材料…@erickson静态无效反转(列表)这是给编译时间error@shikhar这只是一段代码。除非它是语法上有效的方法声明的一部分,否则它不会编译。我不知道所有这些捕获通配符的东西,我发现很难理解,因为我刚刚开始学习泛型…我在哪里可以找到易于理解的主题文档ct?可能吧。当然也有。但我所知道的全面、正确、易懂的东西并不多。(我认为StackOverflow更倾向于这样做,但在其知识方面存在一些差距。)特别是捕获的技术推理实际上非常复杂…我只是在阅读了JLS之后才完全理解它,这是非常令人畏惧的。好的,所以我将推迟到以后,当我对该语言的知识成熟时…现在我只想了解我在做什么,以便编写一些像样的代码。谢谢。
static <T extends Integer> void reverse(List<T> list)
static <T extends Integer> void reverse(List<T> list) {
  List<T> tmp = new ArrayList<>(list);
  for (int i = 0; i < list.size(); ++i) {
    T el = tmp.get(list.size() - 1 - i);
    list.set(i, el);
  }
}
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
T el = tmp.get(list.size() - 1 - i);
T el = (Integer) tmp.get(list.size() - 1 - i);
static <T> void swap2(List<T> list1, List<T> list2) {
    List<T> temp = new ArrayList<>(list1);
    list1.clear();
    list1.addAll(list2);
    list2.clear();
    list2.addAll(temp);
}
static void swap(List<?> list1, List<?> list2) {
    swap2(list1, list2); // <- doesn't compile
}