在JDK1.5后JAVA定义了泛型类、泛型方法、泛型接口,然后编译器会用具体的类型替换它。
第一部分:使用泛型的动机和优点
动机:采用泛型的主要原因是可以在编译期间检测错误,减少在运行期间发生错误的概率。
优点:提高程序的可靠性和可读性
举例程序:
package java.lang
public interface Comparable<T>{
public int compareTo(T o)}
在这里需要知道这以下知识点:1、形式泛型类型;2、泛型实例化;3、泛型类型必须是引用类型;4、自动打包;5、自动解包
1、形式泛型类指的是如上述程序中的<T>这里传递的参数是一个泛型(就是指没有具体的类型,像字符串啊,基本数据类型啊都可以传入相当于没有引入泛型时的Object)
2、在后续处理过程中将一个实际具体的类型替换这个形式泛型类,这就是所谓的泛型实例化。当传入的参数不是一个类型时在编译阶段就会指出来。
3、在实例化的过程中代替形式泛型的必须是引用类型不能是基本类型。比如ArrayList<Integer> = new ArrayList<Integer>()可行,但是ArrayList<int> list= new ArrayList<int>()就是错的。
4、自动打包技术就是指list.add(5)自动将5包装成new Integer(5)
5、自动解包技术就是指将int i = list.get(0);将new Integer(5)自动转换成一个基本类型的值。
第二部分:定义泛型类和接口以及泛型方法
定义泛型类和接口很类似在类的后面声明即可。
定义一个泛型类例如:public class GenericMatrix<T1,T2,T3>{}
定义一个泛型接口例如:public class String implements Comparable<E1,E2,E3>
泛型方法:定义一个方法为泛型类型,要将泛型类型放在方法返回类型之前。例如:<E> void max(E o1,E o2)
第三部分:原始类型和向后兼容
首先要知道原始类型还是属于泛型类型
原始类型的定义:不使用类型参数的泛型类称为原始类型。
比如:Matric stack = new Matric();这种语句等于Matric<Object> stack = new Matric<String>();
注意:原始类型不安全尽量不用,在jdk1.5以后几乎不用原始类型
向后兼容适用于所有的编程,他就是指在程序或者系统更新后旧文档、程序、系统或者在旧类库上开发的程序可以正常使用。
第四部分:通配泛型
首先介绍一下为什么会出现通配泛型:
在有参泛型类中参数为一个对象,在编程过程中可能会传递这个参数的子类型而不是这个参数,这就会导致一些错误。为了避免这种错误的发生就会出现。为了解决这个问题从而引入了通配泛型。
通配泛型有三种形式:1 、?;2、 ? extends T;3、? super T
1、<?>称为非受限通配,它和<? extends Object>一样
2、<? extends T>称为受限通配 :?必须是T的未知子类
3、<? super T>下限通配: ?必须是T的父类或者就是T
第五部分 消除泛型和对泛型的限制
这一部分主要是编译器的工作。
泛型是使用一种称为类型消除的方法实现的,在编写程序过程中编译器使用泛型类型信息编写代码,但是在运行时就水消除泛型取而代之的是原始类型(虽然在编写程序时不用原始类型)。
这里为什么编译器可以将泛型类型转换为原始类型,但是编译期间不建议使用原始类型呢?
原因:泛型主要就是在编译阶段起作用,在运行阶段是不可用的。且使用泛型类型目的就是将可能在运行期间发生的错误在编译阶段发现。而编译器将泛型类型转换为原始类型是在确认泛型类型是安全使用的前提下转换的。也可以说编译器确认泛型类型安全后在运行之前在编译器内部完成自动转换。这样确保在运行期间信息可用。
泛型的限制分四大类:
1、不能使用 new E()即不能使用泛型类型参数用作创建实例,原因:在运行期间泛型类型是不可用的
2、不能使用 newE[ ]即不能使用泛型类型参数创建数组,原因是一样的。
但是可以使用 E [] elements = (E[])new Object[Capacity]代替。
3、在静态环境下不允许类的参数是泛型类型。原因:泛型类型的所有实例共享一套运行时类,因此静态变量、方法就会被共享,这违背了静态变量保护数据的原则
4、异常类不能是泛型
异常主要是捕获可能出现的错误信息并解决的,如果在异常类中使用泛型,则在运行时泛型是不会出现的,从而导致不能捕获到异常所以异常类不能是泛型