泛型的优点
- 类型安全
- 编译器类型转换
- 代码复用
泛型类、接口
- 泛型类,如果没有指定具体的类型,将默认为Object
- 泛型的类型参数只能是类类型(比如Integer, Boolean),不能是基本数据类型(比如int, boolean)
- 泛型类型在逻辑上可以看做是多个不同的类型,但实际上都是相同的类型
- 从泛型类派生子类
- 子类也是泛型类,子类和父类的泛型类型要一致
- 子类不是泛型类,父类要明确泛型的数据类型
class Child<T> extends Parent<T>{
private T demo;
}
class Child extends Parent<String>{...}
泛型方法
- 泛型方法能使方法独立于类而产生变化。实际应用中,建议能使用泛型方法,就不要使用泛型类。
- 如果static方法要使用泛型能力,就必须使其成为泛型方法。
语法:
public <泛型类型形参列表> 返回类型 funcName(泛型类型形参){…}
public class GenericMethod {
//泛型方法对多种类型参数的支持
public <T, E, K> void printType(T t, E e, K k){
System.out.println(t + "\t" + t.getClass().getSimpleName());
System.out.println(e + "\t" + e.getClass().getSimpleName());
System.out.println(k + "\t" + k.getClass().getSimpleName());
}
//泛型方法对可变参数的支持
public <E> void print(E... e){
for (E e1: e){
System.out.println(e1);
}
}
//简单测试
public static void main(String[] args){
GenericMethod gm = new GenericMethod();
gm.printType("abc", 123, 12.3);
gm.printType(true, 123, "123");
Integer[] intArray = {1,2,3};
String[] strArray = {"a", "b", "c"};
gm.print(strArray);
gm.print(intArray);
}
/* 打印结果:
abc String
123 Integer
12.3 Double
true Boolean
123 Integer
123 String
a
b
c
1
2
3
*/
}
类型通配符
- 类型通配符使用"?"代替具体的类型实参
- 类型通配符是类型实参,而不是类型形参
类型通配符的上限
要求该泛型的类型,只能是实参类型,或实参类型的子类类型,语法:
类/接口<? extends 实参类型>
类型通配符的下限
要求该泛型的类型,只能是实参类型,或实参类型的父类类型,语法:
类/接口<? super 实参类型>
可以参考JDK中TreeSet的应用
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
泛型与数组
创建
public class Fruit<T> {
private T[] array;
public Fruit(Class<T> clz, int length){
array = new Array.newInstance(clz, length);
}
}
public class Test{
public static void main(String[] args){
//使用泛型数组,创建一个长度为3的String类型数组
Fruit<String> fruits = new Fruit(String.class, 3);
}
}
泛型擦除
泛型是Java 5之后开始支持,但是用泛型编写的代码依然能够很好地在Java 5之前的版本JVM上正常运行,这是为啥呢?原来Java编译器在编译带有泛型类型的代码时,会进行泛型擦除,使之转化为普通类型,因此JVM完全无法感知泛型概念的存在。