黑马程序员技术交流社区

标题: 关于泛型上限下限的疑问 [打印本页]

作者: hyace    时间: 2014-4-2 22:47
标题: 关于泛型上限下限的疑问
本帖最后由 hyace 于 2014-4-6 15:46 编辑

看毕老师的视频的时候,明白什么是上限什么是下限,但是不明白为什么存元素就要用上限,取元素就要用下限,为什么addAll()就要用上限,实现Comparetor接口就要用下限?谢谢。

作者: 向阳泪无痕    时间: 2014-4-3 08:43
要明白这个问题,你要先弄清楚 什么是上限,什么是下限
上限的意思就是:我们所要存入的元素必须是其子类或本身
下限的意思就是:我们所要操作的元素必须是其父类或本身
所以来看看你的问题,
为什么存入元素要使用上限,因为限定为上限,那我们不就可以放更多类型的元素了吗,比如 Object 为上限,那我们可以放任何元素进去。如果你要是使用下限,那请问,你这里要怎么先用呢,你知道你所要存入的元素到底在那个层次么。
而取元素为什么要使用下限呢?
使用下限表示可以取其父类或本身,如果你这里使用了上限,要是这个上限你搞成 Object了,那你还取得出元素来么。明白了?
作者: 罗安迪    时间: 2014-4-4 09:26
楼上的话说真是到处答题的雷锋同志,哈哈哈

我也墨迹点吧
你处在某层楼中
上限就像天花板,你不能突破天花板获取上一楼的元素嘛,
下限就像地板,当然不能去突破地板去下一层啦。

想突破上下楼就用楼梯咯,即强制转换。泛型不就是为了避免强制转化么。
作者: 黄泉    时间: 2014-4-4 09:38
在写程序的时候,我们希望某一个函数接收的参数,有一个范围的限制,这时候我们就可以考虑使用泛型的上限和下限去解决。我们先看一段代码,然后再去详细解释。

[java] view plaincopy
class Point<T>  
{  
    private T x;  
    private T y;  
    public T getX()  
    {  
        return x;  
    }  
    public void setX(T x)  
    {  
        this.x = x;  
    }  
    public T getY()  
    {  
        return y;  
    }  
    public void setY(T y)  
    {  
        this.y = y;  
    }  
}  
public class Demo2  
{  
//  static void show(Point<? extends Number> p)//此时这个函数只能接收Number及其子类 此时show(p2)会报错  
    static void show(Point<? super String> p)//此时这个函数只能接收String及其父类  此时show(p1)会报错  
    {  
        System.out.println(p.getX());  
        System.out.println(p.getY());  
    }  
    public static void main(String[] args)  
    {  
        Point<Integer> p1 = new Point<Integer>();  
        p1.setX(2);  
        p1.setY(4);  
        Point<String> p2 = new Point<String>();  
        p2.setX("东经43度");  
        p2.setY("北纬34度");  
        show(p1);  
        show(p2);  
    }  
}  
在这段程序中我们定义了一个函数show,我们在参数的后面使用的<? .....>这里的问号,表示的通配符,代表接收的实际参数的类型。我们可以看出来在程序中我先注释了entends的一行代码。这个表示参数的上限,接收的参数必须是Number或者是其子类,如果使用这个的时候,我们调用show方法的时候,传递p2会报错,因为p2不是Number或者其子类。同样的,我们使用super关键字,这个表示参数的上限,程序中表示接收的参数只能是String或者其父类,这时候show方法的参数是p1会报错,不满足下限的要求。
对于上限和下限基本的使用就是这样,希望对你有帮助。

如果哪里写错了,还请指出。
作者: hyace    时间: 2014-4-4 22:33
罗安迪 发表于 2014-4-4 09:26
楼上的话说真是到处答题的雷锋同志,哈哈哈

我也墨迹点吧

你说这是解释啥是上下限,这我懂,可是为什么存用上限,取用下限还是不明白。。。谢谢啊~
作者: hyace    时间: 2014-4-4 22:34
黄泉 发表于 2014-4-4 09:38
在写程序的时候,我们希望某一个函数接收的参数,有一个范围的限制,这时候我们就可以考虑使用泛型的上限和 ...

你这也是解释啥是上下限,还有怎么用,我也明白,可是存取这俩在上下限中的区别还是不懂。。。谢谢啊~
作者: 黄泉    时间: 2014-4-4 22:52
hyace 发表于 2014-4-4 22:34
你这也是解释啥是上下限,还有怎么用,我也明白,可是存取这俩在上下限中的区别还是不懂。。。谢谢啊~ ...

这个要比较起来说明的,设置你所谓的上限下限是在参数声明的时候,其他情况不行
1 首先确定的泛型在new时只能new确定的泛型,且其可以使用add方法添加此类型和其子类的实例
2 如上面说的,这样类型就被定义的死死的,不利于多态,所以才有了<? extends Xxx>这种形式,表示list可以为泛型Xxx或者Xxx的子类型,但是这样也有弊端,就是你不能再用add方法,换句话说这样的泛型只能用来做参数传递读取里面的值,无法添加。
3 那么我还想add怎么办,于是有了<? super Xxx>的形式,这样在作为参数传递时候可以传递Xxx以及Xxx父类型的list进来,但是add只能是Xxx或者Xxx的子类(这个到哪都一样,没什么可说的),至于具体怎么用看你的需求了,好处坏处是参考着来的,谁也没比谁好到哪去,只能说各有各的方式,基本算回答你的问题了,下面的算额外附赠,望采纳
4 List<?> 任何类型可以传递进来,但不能再add
5 List<Object> 只能是类型<Object>,可以add
6 <?>和<? extends Object>意义相同
作者: hyace    时间: 2014-4-5 21:21
黄泉 发表于 2014-4-4 22:52
这个要比较起来说明的,设置你所谓的上限下限是在参数声明的时候,其他情况不行
1 首先确定的泛型在new时 ...

谢谢。。我还得悟下。。但是毕老师确实说的是存的时候用<? extends E>啊,而且Collections的addAll也是这个参数




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2