1.引言
泛型是指参数化类型的能力,可以定义带泛型的方法或类,随后编译器会使用具体的类型来代替它。Java中可以定义泛型类,泛型接口和泛型犯法。
2.优点
使用泛型能够使程序在编译期就抛出异常,避免在运行期发生异常,由于错误在编译时可以被检测到,因此程序更加可靠。 泛型类型必须是引用类型:例如Integer, Double, Float等,而不能是int,double,float。例如给int值创建一个ArrayList,必须这么定义:
List<Integer> list = new ArrayList<Integer>();
那为什么要使用引用类型呢?比如要向上面的list添加一个元素list.add(6)
,Java会自动包装成 new Integer(6)
,这个过程也称为自动打包(autoboxing)。当我们要从ArrayList中取出一个元素时:int a = list.get(0)
,这时候会发生自动解包(autounboxing),即:将包装类型赋值给基本类型。
3.定义泛型类和接口
这很简单:
// 简单泛型类
public class Generic<T> {
List<T> list = new ArrayList<T>();
public int getSize() {
return list.size();
}
}
// 简单泛型接口
// 参考java中的Comparable接口,Java API中String类被定义为实现Comparable接口
public class String implements Comparable<String> {
// todo
}
4.泛型方法
概念: 受限泛型:可以将泛型指定为另外一种类型的子类型,这种泛型称为受限泛型。 非受限泛型:可以理解为泛型类继承Object。<E> 和 <E extends Object>是一样的。 定义泛型方法:
public class Bound {
public static <E extends Generic> boolean equals(E o1, E o2) {
return o1 == o2;
}
}
注意定义泛型类和泛型方法的区别: 泛型类如Generic<E>泛型类型在类名之后,而泛型方法中的泛型类型在方法返回类型之前:public static <E extends Generic> boolean equals(E o1, E o2)
5.泛型通配符
三个概念: 非受限通配:<? extends Object>
受限通配:<? extends T>
T为未知子类 下限通配:<? super T>
T为未知父类 使用场景具体分析,这个应该不难。 ##6.泛型消除 泛型是使用一种成为泛型消除
的方法来实现的。编译器通过泛型类型信息来编译代码,但是随后会消除它。切记,泛型只存在于编译时。 简单说就是:泛型在JVM中会被转换为原始类型来替代!
不管实际的具体类型是什么,泛型类是被它的所有实例共享的。例如:
ArrayList<String> list1 = new ArrayList<String>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
运行时只有一个ArrayList类会被加载的JVM中, list1和list2都是ArrayList的实例,因此list1 instanceof ArrayList
和list2 instanceof ArrayList
都是true。但list1 instanceof ArrayList<String>
是没有错误的,因为JVM无法ArrayList<String>保存为一个类。
6.使用泛型的限制
- 不能使用new E();
- 不能使用new E[]; 不要使用泛型来声明一个数组
- 静态环境下,不允许类的参数是泛型类型。如
public class Test<E> {
public static E o1; // NO!
static {
E o2; // NO!
}
public static void mia(E o) { //NO!
}
}
- 异常类不能是泛型。
7.总结
本文主要是复习一些有关泛型的基础知识,包括泛型的类型,泛型通配,和泛型消除等。要注意的是泛型只是用来在编译是代替具体类型的,在运行时会发生泛型消除,被JVM替换为原始类型。
最后,欢迎大家关注我的个人公众号或者 加我微信点这里: