我对Java中的通配符有一些错误的概念

我对Java中的通配符有一些错误的概念,java,generics,wildcard,Java,Generics,Wildcard,我试图理解如何在Java中使用通配符 import java.util.List; public class WildcardError{ void foo(List<?> i){ i.set(0, i.get(0)); } } public class WildcardFixed{ void foo(List<?> i){ fooHelper(i); } private <T> voi

我试图理解如何在Java中使用通配符

import java.util.List;
public class WildcardError{
    void foo(List<?> i){
        i.set(0, i.get(0));
    }
}

public class WildcardFixed{
    void foo(List<?> i){
        fooHelper(i);
    }
    private <T> void fooHelper(List<T> l){
        l.set(0, l.get(0));
    }
}
import java.util.List;
公共类通配符错误{
无效foo(列表一){
i、 set(0,i.get(0));
}
}
公共类通配符已修复{
无效foo(列表一){
食物助理(i);;
}
私人助理(列表l){
l、 set(0,l.get(0));
}
}
  • 为什么第一个类不能编译而第二个类可以编译
  • 当编译器看到通配符时会发生什么?把它变成物体?类似于第一个类中的
    void foo(对象i)
    ,或者
    void foo(列表i)
  • 类型推断在第二类中是如何工作的
在第一个示例中,您可能传递了一个
列表,因此如果您使用对象设置了一个元素(l.get(0)
的结果),您实际上无法安全地执行该类型。有点近视


在第二个示例中,
l.get(0)
是一个T,非常适合
l.set

解释这一点的好教程

向其中添加任意对象是不安全的,但是:

Collection c=newarraylist();
c、 添加(新对象());//编译时错误
因为我们不知道c的元素类型代表什么,所以我们不能向它添加对象。add()方法接受类型为E的参数,即集合的元素类型。当实际类型参数为?时,它表示某个未知类型。我们传递要添加的任何参数都必须是此未知类型的子类型。因为我们不知道那是什么类型,所以我们不能传递任何信息。唯一的异常是null,它是每种类型的成员

另一方面,给定一个列表,我们可以调用get()并利用结果。结果类型是未知类型,但我们始终知道它是一个对象。因此,可以安全地将get()的结果分配给Object类型的变量,或者将其作为参数传递给预期的Object类型的变量

当我这样做时:

import java.util.ArrayList;
import java.util.List;

public class Wildcard {

    public static void main(String[] args) {
    WildcardFixed wf = new WildcardFixed();
    List<Integer> li = new ArrayList<>();
    li.add(0);
    wf.foo(li);
    System.out.println("Success");
    }
}

class WildcardError{
    void foo(List<?> i){
        i.set(0, i.get(0));
    }
}

class WildcardFixed{
    void foo(List<?> i){
        fooHelper(i);
    }
    private <T> void fooHelper(List<T> l){
        l.set(0, l.get(0));
    }
}
import java.util.ArrayList;
import java.util.List;

public class Wildcard {

    public static void main(String[] args) {
    WildcardFixed wf = new WildcardFixed();
    List<Integer> li = new ArrayList<>();
    li.add(0);
    wf.foo(li);
    System.out.println("Success");
    }
}

class WildcardError{
    void foo(List<?> i){
        i.set(0, i.get(0));
    }
}

class WildcardFixed{
    void foo(List<?> i){
        fooHelper(i);
    }
    private <T> void fooHelper(List<T> l){
        l.set(0, l.get(0));
    }
}
import java.util.ArrayList;
import java.util.List;

public class Wildcard {

    public static void main(String[] args) {
    WildcardFixed wf = new WildcardFixed();
    List<Integer> li = new ArrayList<>();
    li.add(0);
    wf.foo(li);
    System.out.println("Success WildcardFixed");

    WildcardWithT wt = new WildcardWithT();
    wt.foo(li);
    System.out.println("Success WildcardWithT");
    }
}

class WildcardError{
    void foo(List<?> i){
        i.set(0, i.get(0));
    }
}

class WildcardFixed{
    void foo(List<?> i){
        fooHelper(i);
    }
    private <T> void fooHelper(List<T> l){
        l.set(0, l.get(0));
    }
}

class WildcardWithT {
    <T> void foo(List<T> i) {
    i.set(0, i.get(0));
    }
}