Java 泛型机制解析

一、泛型解析

Java泛型编程是JDK1.5版本后引入的。泛型让编程人员能够使用类型抽象,通常用于集合里面。
不使用泛型:
  
  
Map m =newHashMap();
m.put("key","blarg");
String s =(String) m.get("key");
使用泛型:
   
   
Map<String,String> m =newHashMap<String,String>();
m.put("key","blarg");
String s = m.get("key");
以上二个例子已经说明的泛型的使用以及存在的意义。虽然只是多了一个类型转换,但这个操作可能导致类型转换异常ClassCastException,运行时异常往往让人难以检测到。保证列表中的元素为一个特定的数据类型,这样就可以取消类型转换,减少发生错误的机会, 这也是泛型设计的初衷。

二、通配符

//不使用泛型
staticvoid print(Collection c){
Iterator iterator = c.iterator();
for(int i=0,len = c.size();i<len;i++){
System.out.println(iterator.next());
}
}
//使用泛型
staticvoid printTwo(Collection<Object> c){
for(Object object : c){
System.out.println(object);
}
}
//使用类通配符
staticvoid printThree(Collection<?> c){
for(Object object : c){
System.out.println(object);
}
}


以上三个方法的比较。在方法二中只能接受元素类型为Object类型的集合如ArrayList<Object>(),如果是ArrayList<String>,则会编译时出错。因为Collection<Object>并不是所有集合的超类。
方法三中使用了通配符?指定可以使用任何类型的集合作为参数。读取的元素使用了Object类型来表示,这是安全的,因为所有的类都是Object的子类。
常容易被忽略的问题:如果试图往使用通配符?的集合中加入对象,就会在编译时出现错误。需要注意的是,这里不管加入什么类型的对象都会出错。这是因为通配符?表示该集合存储的元素类型未知,可以是任何类型。往集合中加入元素需要是一个未知元素类型的子类型,正因为该集合存储的元素类型未知,所以我们没法向该集合中添加任何元素。唯一的例外是 null,因为 null是所有类型的子类型,所以尽管元素类型不知道,但是 null一定是它的子类型。
   
   
List<?> a =newArrayList<String>();
a.add(null);
边界通配符:
  • 如果你想从一个数据类型里获取数据,使用 ? extends 通配符
  • 如果你想把对象写入一个数据结构里,使用 ? super 通配符
  • 如果你既想存,又想取,那就别用通配符。

三、泛型方法

注意泛型方法的格式,类型参数<T>需要放在函数返回值之前。然后在参数和返回值中就可以使用泛型参数了。
   
   
publicstatic<T>void test(List<T> arrs){
//do something
}

四、常见问题

编译出错:类型擦除问题: List<String>List<Integer>在运行事实上是相同的类型。他们都被擦除成他们的原生类型,即List
   
   
publicvoid test(List<String> ls){
System.out.println("Sting");
}
publicvoid test(List<Integer> li){
System.out.println("Integer");
}
泛型和子泛型问题:
   
   
List<Apple> apples =newArrayList<Apple>();//1
List<Fruit> fruits = apples;//2

第1行代码显然是对的,但是第2行是否对呢?我们知道Fruit fruit = new Apple(),这样肯定是对的,即苹果肯定是水果,但是第2行在编译的时候会出错。这会让人比较纳闷的是一个苹果是水果,为什么一箱苹果就不是一箱水果了呢?可以这样考虑,我们假定第2行代码没有问题,那么我们可以使用语句fruits.add(new Strawberry())(Strawberry为Fruit的子类)在fruits中加入草莓了,但是这样的话,一个List中装入了各种不同类型的子类水果,这显然是不可以的,因为我们在取出List中的水果对象时,就分不清楚到底该转型为苹果还是草莓了。

通常来说,如果FooBar的子类型,G是一种带泛型的类型,则G<Foo>不是G<Bar>的子类型。这也许是泛型学习里面最让人容易混淆的一点。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值