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的子类是没有问题的  

 

带有通配符的字符串和另一个字符串进行匹配(转载加修改)

字符串匹配,通配符匹配,很常见的一个功能,但是却一直没花时间去做。 今天自己在想,做字符串处理,想到的方法有完全遍历,KMP,还有BM,不过由于长期做业务,算法的东西,都忘光了,想来想去还是上网找个...
  • zhanlanmg
  • zhanlanmg
  • 2016年11月09日 23:44
  • 857

通配符、拼接字段

通配符有些像其他语言中的正则表达式,在过滤模糊值时会很有用。通配符本身实际上是SQL的WHERE子句中有特殊含义的字符,SQL支持集中通配符。为在搜索子句中使用,必须使用LIKE操作符。通配符搜索只能...
  • u012582664
  • u012582664
  • 2017年02月20日 13:49
  • 420

java 中关于*号的通配符使用

java 中关于*号的通配符使用1>在java中是用’ .*来代替  *    ,  用 . 来匹配 ?2>正规式   data.*/.dat   相当于data*.dat  import jav...
  • xymyeah
  • xymyeah
  • 2008年05月21日 12:37
  • 5454

Java 泛型通配符解释

前言 最近看Rxjava retrofit 中到处都是泛型类型定义,不得不重新整理一下资料,简单介绍,满足基本理解使用。定义什么是泛型?泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形...
  • o279642707
  • o279642707
  • 2017年04月06日 16:45
  • 571

Java 泛型通配符?解惑

一、通配符的上界 既然知道List并不是List的子类型,那就需要去寻找替他解决的办法, 是AnimalTrianer.act()方法变得更为通用(既可以接受List类型,也可以接受List等参...
  • Baple
  • Baple
  • 2014年05月05日 15:53
  • 35196

动态规划——通配符匹配算法

-----Edit by ZhuSenlin HDU 设计通配符匹配算法,其中*号可以匹配任意多个字符,?号可以匹配任意一个字符。例如12345和12*、12*?以及12*4?等都匹配。 函数原型为:...
  • wumuzi520
  • wumuzi520
  • 2012年03月21日 15:56
  • 6047

关于java中通配符的使用规则

关于java中通配符的使用规则(简单易懂)
  • u012291108
  • u012291108
  • 2016年05月17日 22:20
  • 1840

java 递归实现通配符匹配

/**      *      * 字符串中存在星号(表示多个字符)匹配      * @param pattern  包含星号的字符串      * @param str  要匹配的字符串 ...
  • tianwei7518
  • tianwei7518
  • 2014年01月03日 10:14
  • 1349

java调用linux命令 传递多个参数和通配符的问题

简单的不带通配符linux命令调用非常简单,使用Runtime.getRuntime().exec(command)即可,如果要显示错误,或者   输出信息,得到相应的inputStrea...
  • gredn
  • gredn
  • 2014年06月09日 18:51
  • 568

Java泛型和通配符那点事

泛型(Generic type 或者generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法...
  • xiangzhihong8
  • xiangzhihong8
  • 2016年06月24日 08:45
  • 2040
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java 通配符 问题
举报原因:
原因补充:

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