Jdk1.5新特性之泛型(-)

Jdk1.5新特性之泛型(-)

1.泛型的概念:是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递。“泛型”这个术语意思是:适用于许多许多的类型。

2.为什么要使用泛型?

 有许多原因使得泛型的出现,而最重要的一个原因就是为了更好的创造容器类(java的集合类)。容器,顾名思义,就是一个存储东西的地方。我们以前所学的数组就是一个容器,不过与数组相比,容器类更加的灵活,具备更多的功能。但是容器类有个缺点:当我们把一个对象放进容器后,容器就会“忘记”该对象的数据类型,当取出该对象时,该对象的编译类型就被当做Object来处理(运行类型不变)。Java的开发人员把它设计成这样是为了更好地通用性。但是这样做也就会有两个问题:

1.容器对装入对象的类型没有任何限制,也就是说,你可以向这个容器中放入Dog对象,同时你还可以向这个容器中放入Cat对象,那么问题来了,当你取得时候就可能发生异常了。

2.因为把对象放入容器类后,该对象类型信息被丢失,容器只知道它自己装的类型是Object的,也就是说所有东西都是Object的,所以取对象时还需要强制类型转换,这样子做不仅会增加编程的复杂度,而且有时还会出现ClassCastException。

 

看一下代码:

@SuppressWarnings({ "rawtypes""unchecked" })

public static void main(String[] args) {

List list = new ArrayList();

list.add("love java");

list.add("love 生活");

list.add(23);

for(Object objL:list){

 String s=(String)objL;

 System.out.println(s);

}

}

当运行后就会出现异常:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

 

从某种意义上说,最简单的容器数组这一点还是做得很好的(当然Object类型数组除外),因为数组类型是确定装入某种类型的。

3.手动实现编译时检查类型

我们可以看见容器在编译时是不区分类型的,如果你希望给某一个容器添加的固定类型的对象,那么我们可以自己做编译检查,看一下代码:

import java.util.ArrayList;

import java.util.List;

 

public class AddStr { 

 

@SuppressWarnings("rawtypes")

private List list = new ArrayList();

 

@SuppressWarnings("unchecked")

public boolean add(String ele){

return list.add(ele);

}

public String get(int index){

return (String)list.get(index);

}

public int size(){

return list.size();

}

}

这是自己定义的一个添加字符串的容器,其实根本没做什么,都是ArrayList做的事情,下面看测试代码:

 

 

 

我们可以看到,当你试图添加非字符串对象时,那么编译就不会通过,这是因为我们自己定义的容器类的add方法对ArrayList的add方法做了个封装,也就限定该容器只能装字符串对象了。同时,在CheckPyte类中,我推荐了几本学习java的书籍。

从健壮性角度上看,这种方式还是很有用的,在编译时就做到了类型的检查了。这种做法虽然有效,但局限性很明显,我们需要定义大量的这种类来封装list对象。

 

4.引入泛型

 泛型的格式:  <数据类型>

 注意:此处的数据类型只能是引用类型。

利用泛型,使得List集合只能装字符串对象,看下面代码:

 

我们可以看到泛型就是在List基础上加了一个<String>,这就是使用了泛型了,表示这个List集合只能存放String,不能存放其他,并且从这个集合取出元素时,也不需要进行强制转换了。上面的代码不仅更加健壮,程序再也不能“不小心”的把其他对象“丢进”list集合中了。而且程序更加简洁,集合自动记住集合元素类型,所以没必要对集合元素强制类型转化了。

 

5.泛型中的一些术语

 在jdk帮助文档中我们经常看到使用泛型的一些类,比如:ArrayList<E>,还有我们定义过的ArrayList<Integer>;

(1)整个称为ArrayList<E>泛型类型。

(2)ArrayList<E>中的E称为类型变量或类型参数,并且这个E只能是引用类型。

(3)整个ArrayList<Integer>称为参数化的类型。

(4)ArrayList<Integer>中的Integer称为实际类型参数。

(5)ArrayList<Integer>中的<>读作type。

(6)ArrayList称为原始类型。

 

7.我们从上面的代码中也可以看出参数化类型和原始类型是兼容的,不过编译器报告警告。如:

Collection<Stringcoll=new ArrayList();

Collection coll2=new ArrayList<String>();

 

在这里值得注意的是:参数化类型不考虑类型参数的继承关系,也就是说 ArrayList<Object> list = new ArrayList<String>;这样是错误的。类型参数严格说明集合中装入数据类型是什么和可以加入什么类型的数据,要记住的是:ArrayList<Object> 和ArrayList<String>是没有转换关系的参数化类型。

我们来分析一下为什么不能考虑继承:

如果ArrayList<Object> list = new ArrayList<String>;这句话成立的话,那么ArrayList<Object> list就是说可以向list装入任何对象,然而右边ArrayList<String>表明实际上指向的集合只能装String类型对象,这样也就矛盾了。

对象使用泛型,还有一点也值得注意:泛型与数组不能一起使用,也就是说Vector<Integer> [] vector = new Vector<Integer>[5];这样做是错误的。

下面我们来看看一个小小的思考题:

ArrayList list = new ArrayList<Stirng>;  ①

ArrayList<Object> arrObj = list;    ②

那么,这两句代码在编译期会不会报错呢?

实际上编译器不会报错,第一条把参数化类型给原始类型不会报错,第二句把原子类型给参数化类型也不会报错。我们不能把两句连起来看,因为编译器一句一句的执行,是一个严格按语法检查的工具,不考虑运行时的效果。

 

还有其他的泛型知识,在下一章会给出。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值