泛型是java1.5后推出的新特性之一。通过使用泛型,我们可以更加灵活的指定java中代码的类型,从而程序可以更加灵活。
泛型通配符一般有三种,第一种是<?> 无限定通配符;
第二种<? extends E> 固定上限通配符,类型只能是E或E的子类;
第三种<? super T> 固定下限通配符,类型只能是T或T的父类;

public class FxTest {

    public void addTest1 (List<?> list){
        list.add(1);//编译错误
        Integer a =list.get(0);//编译错误
    }
   public void addTest2(List<? extends Number> list){
       list.add(1);//编译错误
       Number a =  list.get(0);
   }

   public void addTest3(List<? super Integer> list){
       list.add(1);
       Integer a = list.get(0);//编译错误
   }
}

如果我们使用以上三种通配符我们需要注意几点。在使用无限定通配符时,不能在其方法内使用add()和get()方法。使用固定上限通配符时,不能使用add()方法,因为集合不知道传入的参数是什么类型。使用固定下限通配符时,不能使用get()方法。因为集合返回的类型不能确定。

而在阿里巴巴手册也有这么一句强制要求:

java泛型 FastJson Java泛型通配符_编译错误


根据上面代码演示我们也知道为什么有这样的规定了,他会让我们代码的健壮性更强。

总结:
我们要记住这么几个使用原则, 有人将其称为PECS(即"Producer Extends, Consumer Super", 网上翻译为"生产者使用extends, 消费者使用super", 我觉得还是不翻译的好). 也有的地方写作"in out"原则, 总的来说就是:

in或者producer就是你要读取出数据以供随后使用(想象一下List的get), 这时使用extends关键字, 固定上边界的通配符. 你可以将该对象当做一个只读对象;
out或者consumer就是你要将已有的数据写入对象(想象一下List的add), 这时使用super关键字, 固定下边界的通配符. 你可以将该对象当做一个只能写入的对象;
当你希望in或producer的数据能够使用Object类中的方法访问时, 使用无边界通配符;
当你需要一个既能读又能写的对象时, 就不要使用通配符了.