java string通配符_java通配符

找了找关于java通配符的一些资料,下面两则写的比较清晰

1.java通配符

下面是正文:

固定的泛型类型系统使用起来并没有那么令人愉快。Java的设计者发明了一种巧妙(仍然是安全的)“解决方案”:通配符类型。

例如:Pair extends B>,表示任何泛型Pair类型,它的类型参数是B的子类,如Pair,但不是Pair。

构造一个方法:

public static void executeFun(Pair p){

p.getFirst().fun();

p.getSecond().fun();

}

不能将Pair传给这个方法,方法的功能受到了很大的限制。解决方法是:使用通配符类型。

public static void executeFun(Pair extends B> p){

...

}

类型Pair是Pair extends B>的子类型。

使用通配符会通过Pair extends B>的引用破坏Pair吗?答案是不能。

Pair bsp = new Pair();

Pair extends B> bp = bsp;//ok

bp.setFirst(new B());//Error

对setFirst的调用有一个类型错误。找知道其中缘由,请仔细看看类型Pair extends B>。它的方法如下所示:

? extends B getFirst();

void setFirst(? extends B);

这样不可能调用setFirst方法。编译器只知道它需要某个B类型的字类型,但不知道具体是什么类型。它拒绝传递任何特定的类型---毕竟,?不能用

来匹配。

使用getFirst就不存在这个问题:将getFirst的返回值赋给一个B的引用是完全合法的。

这就是引入有限定的通配符的关键之处。现在已经有办法区分安全的访问器方法和不安全的更改器方法了。

通配符的超类型限定

通配符限定与类型变量限定十分相似。但是,它还有一个附加的能力,即可以指定一个超类型限定,如下所示:

? super BSub

这个通配符限制为BSub的所有超类型。已有的super关键字十分准确的描述了这种关系。

为什么要这样做?带有超类型限定的通配符的行为与前面介绍的相反。可以向方法提供参数,但不能使用返回值。例如,Pair super BSub>有方法

void setFirst(? super BSub)

? super BSub getFirst()

编译器不知道setFirst方法的确切类型,但是可以用任意BSub对象(或子类型)调用它,而不能用B对象调用。然而,如果调用getFirst,返回的对

象类型不会得到保证,只能把它赋给一个Object,如果要将返回值赋给一个非Object的变量要使用强制的类型转换。直观地讲,带有超类型限定的通

配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。

下面是超类型限定的另一种应用。Comparable接口本身就是一个泛型类型。它被声明如下:

public interface Comparable {

public int compareTo(T o);

}

在此,类型变量指示了o参数的类型。例如,String类实现Comparable,它的compareTo方法被声明为

public int compareTo(String o)

很好,显式的参数有一个正确的类型。在JDK1.5之前,o是一个Object,并且该方法的实现需要强制的类型转换。因为Comparable是一个泛型类型,

也许可以把ArrayAlg类的min方法做得更好一些?可以这样声明:

public static > T min(T[] a){

if(a == null || a.length == 0){

return null;

}

T t = a[0];

for(int i=1;i

if(t.compareTo(a[i]) > 0){

t = a[i];

}

}

return t;

}

看起来,这样写只适用T extends Comparable更彻底,并且对于许多类来讲会工作得更好。例如,如果计算一个String数组的最小值,T就是String

类型的,而String是Comparable的字类型。但是,当处理一个GregorianCalendar对象的数组时,就会出现问题。GregorianCalendar是

Calendar的子类,并且Calendar实现了Comparable。因此GregorianCalendar实现的是Comparable,而不是

Comparable。

在这种情况下,超类型可以用来进行救助:

public static > T min(T[] a){ ... }

现在compareTo(? super T)

有可能它被声明为使用类型T的对象,也有可能使用T的超类型(例如,当T是GregorianCalendar)。无论如何,传递一个T类型的对象给compareTo方

法都是安全的。

对于初学者来说,>这样的声明看起来有点吓人。但很遗憾,因为这一声明的意图在于帮助应用程序员排除调用

参数上的不必要的限制。对泛型没有兴趣的应用程序员可能很快就学会掩盖这些声明,想当然地认为库程序员做的都是正确的。如果是一名库程序员

,一定要习惯于通配符,否则,就会受到用户的责备,还要在代码中随意地添加强制类型转换直至代码可以编译。

无限定通配符

还可以使用无限定的通配符,例如,Pair>。咋看起来好像和原始的Pair类型一样。实际上,有很大的不同。类型Pair>有方法如:

? getFirst()

void setFirst(?)

getFirst的返回值只能赋给一个Object。setFirst方法不能被调用,甚至不能用Object调用。Pair>和Pair的本质不同在于:可以用任意的Object

对象调用原始的Pair类的setFirst()方法。

为什么要使用这样脆弱的类型?它对于许多简单的操作非常有用。例如,下面这个方法将用来测试一个pair是否包含了指定的对象,它不需要实际的

类型。

public static boolean hasNulls(Pair> p){

return p.getFirst() == null || p.getSecond() == null;

}

如果把它转化成泛型方法,可以避免使用通配符类型:

public static boolean hasNulls(Pair p)

但是,带有通配符类型的版本可读性更强。

2.子类型和通配符、

1 子类型和替换原理

在java中,如果它们的关系是通过extends或implements建立的,那么这种关系就是父类型与子类型的关系。

替换原理:能够接受父类的就一定可以接受子类型。

注意:List和List不存在子类型关系。但是数组的行为就有所不同:

Integer[] 是Number[]的子类型。

2 拥有extends的通配符

extends E>表示E类型的任意子类型(包括本身),而这?就叫做通配符,也就是任意类型。

public static void count(Collection extends Integer> ints, int a) {}

3 拥有super的通配符

super T>表示T类型的任意父类型(包括本身)。

public static void count(Collection super Integer> ints, int a) {}

4 Get和Put原理

我们怎样决定使用哪种类型的通配符,用extends还是super,或两者都不。

Get和Put原理:当你仅仅从一个结构中获取值时,你应该使用extends。如果只想向一个结构中插入值,你应该使用super。如果想即插入又获取值时

,你因该避免使用通配符。说白了就是放入的条件越宽越好,因为超类能够接受他的任何子类。而取值是越明确越好,所以用子类限定,同时也限制

了插入的范围。

null是属于任何引用类型,而Object是任何类型的超类。

5 数组

在java中,数组子类型是协变的,也就是说当S是T的子类型,那么S[]就是T[]的子类型。相反,List并不是List的子类型。但如果引入通配符

,即List被认为是List  super T>的子类型(S是T的超类型)。

6 通配符捕获

当调用泛型方法时,类型参数可以被用于匹配用通配符表示的未知类型,这叫做通配符捕获。

注意:通配符表示未知类型。

7 通配符的限制

A)实例创建:通配符不能出现在创建对象表达式的顶层,但是嵌套的可以。

List> list = new ArrayList>(); // 编译错误

Map map = new HashMap//编译错误

List> lists = new ArrayList>();//合法。

B) 泛型方法调用:如果调用一个包含明确类型参数的泛型方法,那么这个类型参数一定不能是通配符。你可以采用类型推断或显示的传递一个

类型参数。

List> list = lists.factory();

List> list = lists.factory(); //Object就是明确的类型参数。

List> list = lists.>factory();

但是嵌套的可以:

List> Lists.>factory();//合法

C) 超类:因为创建类实例时,首先要初始化他的父类(创建实例的约束也适合超类),所以在类的声明中,如果超类或接口有类型参数,那么这些

类型参数一定不能是通配符。

class AnyList extends ArrayList>{...} //编译错误

class AnotherList implements List>{...}//编译错误

但是嵌套的可以:

class NestedList implements ArrayList>{...}//合法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值