一、泛型的基本概念
- 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。
- 泛型的作用:
- 1、类型检查:
- 2、类型的强转
- 关于是实现多类型的功能,Object也可以实现,但是Object类型并没有涉及到类型检查。
二、泛型类
- 泛型类(generic class):就是具有一个或多个类型变量的类。以GenericMath类为例
class GenericMath<T >{
public int sumFunc(T[] array){}
}
- 泛型的类型擦除:就是把所有的类型都擦除成原始类型Object类型。如下面代码g1和g2都被擦除成Object类型,而且这个是在编译阶段就已经完成了
GenericMath<Integer> g1 = new GenericMath<Integer>();
GenericMath<Integer> g2 = new GenericMath<Integer>();
System.out.println(g1.getClass()==g2.getClass());
三、泛型方法
- 上面介绍了如何定义一个泛型类,下面介绍一下如何定义带有简单类型参数的简单方法
class GenericMath<T extends Number>{
public int sumFunc(T[] array){
// Number a = new Number(); Object o = new Object();
int sum = 0;
for(T val : array){
sum += val.intValue();
}
return sum;
}
public <E extends Number> int sumFunc2(E[] array){
int sum = 0;
for(E val : array){
sum += val.intValue();
}
return sum;
}
public static <E extends Comparable<E>> boolean compare(E a, E b){
return a.compareTo(b) > 0 ? true : false;
}
}
- 对于上述代码,可以看到:
- 1、在定义泛型类的时,T extends Number,这是对T的类型进行设置上界,不然在编译阶段会把T类型擦除成Object类型,从而导致报错。
- 2、在一个泛型类中,设置多个不同的泛型方法,但是每个泛型方法的作用域必须注意。而且尽量用不同的字母进行区分,一般情况下是T或者E。
四、泛型接口
interface Info24<T> { // 在接口上定义泛型
public T getVar(); // 定义抽象方法,抽象方法的返回值就是泛型类型
}
// 定义泛型接口的使用
class InfoImp24<T> implements Info24<T> { }
五、注意事项
- 1、不能直接new泛型类型的对象
//编译器不知道泛型类型T到底是什么类型
T a = new T();
//应该这样定义
GenericMath<Integer> obj1 = new GenericMath<Integer>();
- 2、不能直接new泛型类型的数组
T[] arr = new T[5];//error
//等价于
T[] array = (T[])new Object[5];
//因为编译器不知道T是什么类型
- 3、static方法不能使用泛型类定义的泛型参数T,因为静态方法都需要类型来调用,而不是对象来调用,使用泛型参数T调用,编译器也不知道它是什么类型。
//静态泛型方法
public static <E extends Comparable<E>> boolean compare(E a, E b){
return a.compareTo(b) > 0 ? true : false;
}
- 4、不能定义泛型类的数组
GenericMath<Long>[] g3 = new GenericMath<Long>[5];
- 这有什么问题呢?因为擦除之后,g3的类型是GenericMath[],在类的内部,泛型类型就是被基类型代替的(默认是Object类型),而对外,所有返回值类型为泛型类型的方法,在真正使用返回值之前,都是会经过类型转换的。
- “编译的时候通过增加强制类型转换的代码,来避免用户编写出可能引发ClassCastException的代码”。这其实也算是Java引入泛型的一个目的。如果允许了泛型数组,那么编译器添加的强制类型转换的代码就会有可能是错误的。
Integer[] intArray2 = new Integer[10];
//intArray2[0] = new String("hello world");//会报错!
Object[] obj1 = intArray2;
obj1[0] = new String("hello world");//这样就实现了
- 5、泛型代码需要检查是否需要制定上界
public static <E extends Comparable<E>> boolean compare(E a, E b){
return a.compareTo(b) > 0 ? true : false;
}
- 对于此代码如果不设置Comparable上界就不可以用compareTo方法。
- 6、两个引用类型互相为继承关系,本来可以基类引用派生类对象的,但是,该两个类型作为泛型类的实例化类型,互相是不能够引用的!