您的位置:首页 > 职场人生

黑马程序员——java基础——泛型

2015-06-12 14:26 405 查看
一, 什么是泛型

泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。Java中的泛型是Java5.0出现一种安全机制,是一种编译时期的技术。

二,怎么表示泛型

Java中用<>来表示泛型,<> 中间的内容通常是用单个大写字母来表示比如:<T>   。<qq,tt>这中写法也不错只不过阅读性差。

三, 泛型中的基本术语

以ArrayList<E>为例   ,<>念着typeof,   ArrayList<E>中的E称为类型参数变量,ArrayList<Integer> 中的 Integer成为实际参数类型,整个ArrayList<E>称为泛型类型 ,   整个 ArrayList<Integer>称为参数化的类型 。

四,泛型的好处

A:它的出现提高了程序的安全,让程序的一些在运行时期可能出现的问题,转移到编译时期。(ClassCastException)

B:避免了强制装换的麻烦。

下面用一个例子来阐述泛型的优点

//创建一个arraylist集合
ArrayList list=new ArrayList();
//往集合中添加元素
list.add("aa");
list.add("bb");
list.add("cc");
list.add("cc");
list.add(new Integer(2));
//遍历集合
for(Iterator  it=list.iterator();it.hasNext();)
{
String str=(String)it.next();
System.out.println(str);
}

直接运行上面的代码肯定会抛出异常(java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String)我们很容易就找出抛异常的地方 ,我们往集合中添加的第五个元素一个Integer 类的   而在下面遍历的时候我们把强制装换成String所以就会抛异常。这样的代码在编译的时候没有问题而在运行时就会出现问题,所以安全性不高,并且需要我要我们去强转。(强制装换的原因 在Java1.4之前没有泛型机制,其实ArrayList 集合的add 方法参数的类型是Object类型,并且 通过迭代器的next()的返回值的类型 也是Object 类 ,所以就需要我们进行向下转型。

到了Java5.0 出现了泛型机制

//创建一个arraylist集合
ArrayList<String> list=new ArrayList<String>();
//往集合中添加元素
list.add("aa");
list.add("bb");
list.add("cc");
list.add("cc");

list.add(new Integer(2));
//遍历集合
for(Iterator<String>  it=list.iterator();it.hasNext();)
{
System.out.println(it.next());
}

上面的代码是不能通过编译的   这样就将在运行时出现的问题转移到了编译时候,这样我们就知道程序有问题,就去修改代码。要想通过编译就将list.add(new Integer(2));注释掉。注释掉之后上面的代码就可以正常运行了,并且和最初没有加入泛型的代码作比较发现,加入泛型之后可以省去强转。

  
五 , 泛型的擦除和补偿
加入了泛型的代码在经过javac编译之后的字节码文件中是不带有泛型的(因为泛型是编译器的技术)这就是泛型的擦除。既然字节码文件中不存在泛型的话,那么为什么最后我们不需强转,这是因为泛型补偿机制的存在,由于有这个补偿机制的存在,在我们遍历集合的时候在底层帮我们完成强转,所以就不需要我们自己去实现强转。

六,  泛型类,接口,方法,限定。

A:泛型类
在定义一个类型的时候 由于这个类操作的引用数据类不确定,就可以加入泛型。
格式:public class 类名<类型参数变量1.....> {}比如:public class ArrayList<E>
我们也可以自定义一个泛型类
public class Tool<E> {

public E test(E e)
{
E t=e;
return t;
}

}


这样我们定义好了加入了泛型机制这个Tool工具类

B:泛型方法

在定义一个方法的时候 加入泛型   
格式 :访问修饰符  <类型参数变量1.....>  返回值  方法名(参数列表)    (一般泛型方法都会在返回值和 方法的参数列表中用到 该方法上定义的泛型)  比如:Collection接口中的toArray()      <T> T[]toArray(T[] a)

自定义泛型方法
public <Q> void test(Q q)
{
[....]
}

 
C:泛型接口
在定义接口的加入泛型
格式: 格式:public interface 接口名<类型参数变量1…>  比如:public interfaceIterator<E> 

自定义泛型接口
public interface Tool<T> {
public void test(T t);

}


D:泛型通配符
格式:<?>  就是用?表示类型参数     表示这个泛型接受的类型可以是任意的

E:泛型的限定
a, 上限
格式 :<? extends E>   比如:<? extends Person> 表示这个泛型接受的类型只能是Person或者Person 的子类(包括整个子类体系中的类)   其实上面的泛型通配符就是<? extends Object>
通常对集合中元素进行存储操作的时候用上限。
b,下限
格式:<? extends E> 比如:<? super  Person> 表示这个泛型接受的类型只能是Person或者Person的父类(包括整个父类体系中的类)

通常在对集合中的元素进行取出操作的时候用下限

七:泛型注意的地方:
A:当泛型方法是静态的时候,不能使用该方法所在的类上面定义的泛型,要在该静态方法上自己定义泛型。
B:在定义泛型方法的时候,泛型要定义在访问修饰符之后,返回值之前。
C:使用泛型的时候保证左右两边的泛型一样。但是只有一边带有泛型的话是可以 比如 ArrayList<String> list1=new ArrayList(); //ok      ArrayList list2=new ArrayList<String>();//ok     这种OK 的原因是兼容以前没有出现泛型之前的代码。
D: 使用泛型通配符的时候 不能像下面一样
public void test(Collection<?> e)
{
//.......

for(Iterator<?> it=e.iterator();it.hasNext();)
{
//这种用法是错误的
? t=it.hasNext();

}

}
E:子类在实现带有泛型的接口的时候 子类可以丢弃接口的泛型也可以继续使用接口的泛型。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息