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

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

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

2.为何要使用泛型?数组

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

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

2.由于把对象放入容器类后,该对象类型信息被丢失,容器只知道它本身装的类型是Object的,也就是说全部东西都是Object的,因此取对象时还须要强制类型转换,这样子作不只会增长编程的复杂度,并且有时还会出现ClassCastException。测试

 

看一下代码:spa

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

public static void main(String[] args) {对象

List list = new ArrayList();blog

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;    ②

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

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

 

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