A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 水云间 中级黑马   /  2013-5-27 13:01  /  1203 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

这些天在学习泛型,一直搞不懂泛型通配符和泛型限定,什么是泛型通配符和泛型限定?他的作用是什么?该怎么用?请高手们指点,最好有代码的示例,不胜感激

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

3 个回复

倒序浏览
People p=new People();
  List<? extends User> list=new ArrayList<People>();
    list.add(p);

像你这个代码,如果list.add(p);加的不是一个People,那会怎么样呢?假设另一个类Man继承于User,且Man与People没从属关系。那么然后按照List<? extends User> list来理解,将Man加到list里面应该是没问题的吧。可是另一方面我们定义的list是一个new ArrayList<User>(),这样看的话把Man加到list里面貌似就呃掉了吧。

而按照freish的说法也是不那么对的样子。因为如果存在这么一个函数f(List<? extends Number> LN),在这里函数里,我们限制了输入的参数LN必须只能存放数字类Number,这样一个限制应该是很有用的吧,可以避免你把一个List<String>或者其他东西传给函数f()。如果按照freish的方法,我们把? extends Number直接写为Number的话,那么你f(new ArrayList<Integer>())这样写的话编译器会华丽丽的报错,所以这么改又是不对的。

在你这个问题里面的话,把list写出 List<? extends User> list 是没什么实际意义的,但是如果像是在上面函数f(List<? extends Number> LN)里的话确是有意义了。也就是说理论上来说,通配符是被设计成一个有用的东西的,也就是用来限定传入函数的参数的(或者赋值时来限定等号右边的)。而通过通配符来限定是某某某的子类或者超类在list这种容器应用的时候却产生了矛盾,也就是上面说的你本来只是想把People给加到list的,结果却一不小心把人家Man给加进来了。这样看来的话,java应该是考虑到这种情况了,所以就? extends User 成什么乱七八糟的 capture#105 of ? extends User类型了。泛型产生的原因就是当时的list这些容器能把任何类型的东西存进去又再拿出来(因为是Object),这样容易产生混乱。所以就产生了泛型来限制和检查类型。而这种限制却在这些特殊的情况下面产生了矛盾。

嗯,所以总结来说,你不能这么写代码,不能把要操作到泛型参数的方法的类声明为带有通配符的模式。还有一些例子看起来好似能通过编译的,实际确是不行的。比如说
class People<K,V> extends User{
    void f(K k){System.out.println("f(K k)");}
    void f(V v){System.out.println("f(V v)");}
}
在这里f有着两个不同类型参数K和V,看起来好像没事儿的样子。但是这是不能编译成功的。

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
泛型限定是这样:<T super xxx>或者<T extends xxx>
泛型通配符是这样:<?>
泛型限定是限定了类型变量可以指定的范围。泛型通配符代表任意类型,但是要注意:泛型通配符只能用于引用的声明中,不可以在创建对象时使用;不可以使用采用了泛型通配符的引用调用使用了泛型参数的方法。另外,通配符也是可以跟泛型限定的,可以看下面贴的代码。
  1. public class FanXing {
  2.         public static void main(String[] args) {
  3.                 Apple<String> appleStr=new Apple<String>();
  4.                 appleStr.setColor("红色");
  5.                
  6.                 Apple<Integer> appleNum=new Apple<Integer>();
  7.                 appleNum.setColor(1);
  8.                
  9.                 SayColor(appleStr);
  10.                 SayColor(appleNum);
  11.         }
  12.         
  13.         static void SayColor(Apple<? extends String> apple){
  14.                                 System.out.println(apple.getColor());
  15.         }
  16. }

  17. class Apple<T>{
  18.         private T color;
  19.         public void setColor(T color){
  20.                 this.color=color;               
  21.         }
  22.         public T getColor(){
  23.                 return this.color;               
  24.         }
  25. }
复制代码
上面的代码会抛出这样的异常:
  1. net\oseye\FanXing.java:12: 错误: 无法将类 FanXing中的方法 SayColor应用到给定类型
  2. ;
  3.                 SayColor(appleNum);
  4.                 ^
  5.   需要: Apple<? extends String>
  6.   找到: Apple<Integer>
  7.   原因: 无法通过方法调用转换将实际参数Apple<Integer>转换为Apple<? extends String
  8. >
  9. 1 个错误
复制代码
这就是限定起的作用。

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
这个多用就明白了。我开始也搞不清。天天用就清除了。我就不打字回答了 去把视频再看一遍应该就了然了。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马