java 通配符 问题

转载 2011年01月13日 11:25:00

java 通配符问题,困惑了好久的一个问题,觉得这篇文章将解的最清楚明白:

 

List<Fruit> fruit = new List<Apple>() ;

这是因为List<Fruit>是持有Fruit或其导出类的容器,而List<Apple>是持有Apple的容器,它们之间并没有类型上的相关性。所以如果真的想达到这种目的,可以借用通配符的作用:

List<? extends Fruit> fruit = new List<Apple>() ;

这样,就可以可以通过编译器的检查了。在这里,List<? extends Fruit>实际上并不是指这个List可以持有任何类型的

Fruit,通配符引用的是明确的类型,所以它的意思是某种指定的具体类型,所以编译器只是知道它可能是持有Apple的

List,也可能是持有Orange的List,或者其他持有其他具体类型的Fruit的List,所以上面的可以通过,然而正是这种不确定性导致了一些不愉快的情况发生:

fruit.add(new Apple()) ;  //compile-time error

fruit.add(new Fruit()) ;  //compile-time error

奇怪啊!怎么把它们放进去都是出错呢?我想可能是这样,既然fruit是持有某种具体类型的List,但是编译器并不知道是哪种,你随便放一个进去,是正确的吗?这一点连编译器都无法判断,怎么能随意就通过编译器的检查呢?于是就出错了。但是如果你真的用一种神奇的方法(事实证明这种神奇的方法是存在的)将某个对象加进去,试图想将它取出时,编译器知道它至少是一个Fruit,所以你可以这样是行得通的:

Fruit f = fruit.get(0) ;

其实这个无法通过编译的本质原因是Java设计者在捣鬼,查看List的源代码,会发现add的方法是这样的:

boolean add(E e) ;

在这里(以上代码是我从源代码中复制过来的)E是代表泛型参数,所以当E是<? extends Fruit>的时候,调用add方法时就要通过检查,因此无法通过。如果参数类型是Object,这样无论什么类型都是Object,所以就可以调用了,比如:

boolean contains(Object o) ;

boolean remove(Object o) ;

以下代码是个简单的应用举例:

LIst<? extends Fruit> fruit = Arrays.asList(new Apple()) ;

fruit.contains(new Apple()) ;

fruit.indexOf(new Apple()) ;

fruit.remove(new Apple()) ;

 通配符的另一个应用是与super结合:List<? super T> 。顾名思义,这是持有任何T的基类的容器。那样是不是所有T的基类都可以放进去呢?同样编译器是无法知道是哪个具体的T的基类,所以无法检查,所以编译器就不能确保安全性,所以就无法通过。但是无论是哪一个具体的基类,但是如果是放入T或者是T的基类都是可以的,因为它们可以安全的向上转型而不会出现任何差错。

还有一种通配符的用法是“?”的孤军奋战:List<?>。这个我也可以来一次顾名思义,就是持有任何类型的容器,但是限于某种具体的。然而你会发现,如果没有使用泛型,只有List,它也是可以持有任何类型的,所以编译器一般不会太在意这点区别。但是还是有另一种特殊情形:List<? extends Object>,这就相当有趣,它表示持有Object或从Object继承下来的类的容器,但是在Java中,所有的类都是从Object中继承的,所以它的范围和上面两种情况一概一样的啊!可是在

List和List<? extends Object>的相互赋值是会出现警告,但是List<?>和List<? extends Object>的相互赋值是不会的。这样一种有趣的情形就会出现,如果将List<? extends Object>和List<?>相互赋值,再将List<?>和List相互赋值,这样就实现了 List<?>和List<? extends Object>的相互赋值,且不会出现警告,看以下应用:

public class ExchangeValue{

  static <T> void  f1  (List<T>  list)  {  T  t  =  list.get(0) ;  }

  static void  f2  ( List<?>  list )  { f1(list)  ;}

  public static void main (String[] args){

    List   ls  =  new  List<Integer> (1);

    f1(ls) ;  // warning!!

    f2(ls) ; // warning!!

}

 

 

 

 

下面这个例子也不错,可以好好理解一下:

  1. //Apple Orange 都继承自Fruit类,同时Jonathan是Apple的子类   
  2. List<? extends Fruit> list = new ArrayList<Apple>();   
  3. //list.add(new Apple());Error   
  4. //list.add(new Fruit());Error   
  5.   
  6. List<? super Fruit> list = new ArrayList<Apple>();   
  7. list.add(new Apple());//可以   
  8. list.add(new Fruit());//可以   
  9.   
  10. List<? extends Fruit> list = new ArrayList<Apple>();   
  11. list中为什么不能加入Fruit类和Fruit类的子类呢,原因是这样的   
  12.    List<? extends Fruit>表示上限是Fruit,下面这样的赋值都是合法的   
  13.    List<? extends Fruit> list1 = new ArrayList<Fruit>();   
  14.    List<? extends Fruit> list2 = new ArrayList<Apple>();   
  15.    List<? extends Fruit> list3 = new ArrayList<Jonathan>();   
  16.    如果List<? extends Fruit>支持add方法的方法合法的话   
  17.    list1可以add Fruit和所有Fruit的子类   
  18.    list2可以add Apple和所有Apple的子类   
  19.    list3可以add Jonathan和所有Jonathan的子类   
  20.    这样的话,问题就出现了   
  21.    List<? extends Fruit>所应该持有的对象是Fruit的子类,而且具体是哪一个   
  22.    子类还是个未知数,所以加入任何Fruit的子类都会有问题,因为如果add Apple   
  23.    的话,可能List<? extends Fruit>持有的对象是new ArrayList<Jonathan>()   
  24.    Apple的加入肯定是不行的,如果 如果add Jonathan   
  25.    的话,可能List<? extends Fruit>持有的对象是new ArrayList<Jonathan的子类>()   
  26.    Jonathan的加入又不合法,所以List<? extends Fruit> list 不能进行add   
  27.   
  28.       
  29.    而List<? super Fruit> list 表示list持有的对象是Fruit的父类,下限是  Fruit,所以list中add Fruit或Fruit的子类是没有问题的  

 

java泛型中的通配符?问题

本文是经过网上查找的资料整合而来,给自己做个笔记,也分享给大家!需要你对泛型有一定的基础了解。 package Test8_8;import java.util.ArrayList; import j...

java 通配符使用示例

  • 2010年06月21日 16:07
  • 59KB
  • 下载

SpringMVC Controller单元测试静态引入通配符问题

示例iimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import stati...

005——struts2的关于通配符的问题

动态方法调用(Dynamic Method Invocation,DMI):是在action的名字中使用感叹号(!)来标识要调用的方法名 用户名: 密码: public Stri...

字符串转换成整数,通配符的字符串匹配问题

http://blog.csdn.net/v_july_v/article/details/9024123#comments 前言 之前本一直想写写神经网络算法和EM算法,但写这两...

struts2.5版本struts.xml中使用通配符问题

ERROR Dispatcher Could not find action or result: /ssm0602/User_login There is no Action mapped for...

struts有关action配置的通配符配置问题

很多东西总是容易忘,不停的去网上查,现在自己写个博客记录一下,方便以后查阅 虽然一直都在用Struts2 + Hibernate+Spring框架开发项目, 但是项目架构一直都是别人搭建的,里面的...

oracle通配符,运算符的使用, 冒号问题

用于where比较条件的有 :      等于:=、=、           >,=.

关于component-scan中base-package包含通配符的问题探究

今天在配置Spring的component-scan时,发现了一个有趣的问题。就是在指定base-package时,如果使用了星号通配符*,有时会出现类扫描不到的情况。下面研究一下这个问题。先介绍一下...

Struts2一个Action内包含多个请求处理方法的处理,method的使用方法,struts2中的路径问题,通配符映射

Struts2一个Action内包含多个请求处理方法的处理,method的使用方法,struts2中的路径问题,通配符映射 struts2的关于method=“{1}"意思详解   name=...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java 通配符 问题
举报原因:
原因补充:

(最多只允许输入30个字)