废话不多说,直接进入正题。

2个概念 上限通配符 及下限通配符

下面我们看一个程序:


通配符及泛型的若干问题_程序


上限通配符(<? extends Object>)

下限通配符 (<? super Integer>)


说实话,这些概念确实让人很头痛,如果不是那种要去应对考试的,我觉得根本没必要记,知道怎么用就好了,那么接下来 我就帮大家分析下上面出错的原因,让大家更好的理解。


首先看第8行 泛型是<? extends Object>,这个要怎么理解呢?看了一下网上的资料,觉得好难懂,好吧,可能是我智商被压制了。下面我就用我自己理解的,比较简单的话来讲。其实你可以这么理解

他就相当于<?>(?代表任意的一个类) 但是 他给?加了一个条件,就是这个类必须要继承Object,

这时,有人就会问,不是所有类都继承Object这个类吗,那不是所有的类的实例都可以add进来吗没为什么第9,10,11行还会报错呢?恩,当时我也是这么想的,所以闷了好久,然后又想了一下,想通了。

举个例子,我们把?用Integer替换,是不是满足 ? extends Object,那么我们接下来add(new String("asd"));往list1里面加个字符串可以嘛?显然是不可以的。那么String是不是extends Object呢?是的。

所以我们跟本不知道?是代表什么,所以我们可以用各种类去替换“?”,从而排除了任何类的实例都是无法add进list1里面的。所以第9,10,11行出错。

下面我们可以想下,什么能够传入呢?没错,就是null,不管你是什么类型,你肯定是一个类型,我add 一个null进list1是任何情况下都不会出错的。

下面我们可以说一下取的情况,也就是第13,14,15行代码。


因为我们无法判断?是什么,所以我们无法准确的给他一个类型。但是我们知道他的父类是Object,那么直接用Object定义一个变量 当然能存放取出来的对象。



至于下限通配符其实也差不多的。


<? super Integer>


可以用我上面的方式来判断,先用<?>来代替<? super Integer>,然后想,?其实是被加了一个限定条件的,限定条件是:是Integer这个类的父类。

如果你熟练的话,直接解读<? super Integer>,传入的参数必须是Integer的符类型,但是Integer的父类型有很多,所以我们根本不能确定是哪个,但是我们能确定的是,他是Integer的父类,所以你可以add一个Integer实例进list2中。

在接收的时候,我们依然无法准确判断?是哪个类,但我们知道的是他肯定是Object的子类,所以定义一个Object引用变量指向这个取出来的类,这样当然是可以的。



还有一个关键问题是new ArrayList<?>();中 ? 填的是什么呢。

首先 你不能直接用“?”,或者<? extends Object>这种有通配符的标记,会报错的。


然后就是 你填的应该是一个具体的类名,但是你这个类名必须要满足你前面那个约束。

比如 第8行 String是满足<? extends Object>这个的 因为String是继承Object的。


还有就是,如果你前面是一个具体的类,那么你后面必须是与前面相同的具体的类,不能是他的子类,更不能是其他类。


说的有点多,虽然尽量用很通俗的语言了,但是可能还是有疑问的话请给我留言。