1、 泛型的设计背景
参考《java编程思想4.0》中关于jdk 1.5 引入泛型的原因 , 有两点:
- 1.1 多态有类型的范围限制,当想设计一个类,让其中用到的类型更通用时,多态无法满足。
在java中,当我们为了让程序更易扩展、或者让代码更灵活,首先会考虑使用继承,或者接口进行设计(多态),但是这两种方式总会有一个使用范围限制。使用继承必须是基类的扩展类,使用接口则必须实现该接口。
附如下代码(继承方式),Test 类drawSth(Shape shape) 的入参必须是Shape的子类。
public abstract class Shape{
public abstract void draw();
}
class Circle extends Shape{
@Override
public void draw() {
System.out.println("a Circle");
}
}
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("a Triangle");
}
}
class Test{
public void drawSth(Shape shape){
shape.draw();
}
public static void main(String[] args) {
Test test = new Test();
test.drawSth(new Circle()); //多态:向上造型
test.drawSth(new Triangle());
}
}
- 1.2 容器技术,一个类持有大量对象时,方案更优雅(如集合ArrayList<T>的设计)
2 、泛型的基本使用
- 声明:使用一对 <> 声明,按使用位置分 泛型类、泛型方法、泛型接口
//泛型类 (也是对象持有技术的一种,另有继承,组合)
public class Test<K,V,H> {
private K q;
private V q1;
private H q2;
}
//泛型方法
public <K> K ddd(){
return null;
}
//泛型接口
public interface Test<T> {}
- 通配符边界
无界: eg: LIst<T>
上界: eg: List <? extends String>
下界 : eg: List<? super String>
3、使用注意
3.1 只是作用在方法上的话,尽量使用泛型方法,让读者更明确泛型的目的
3.2 声明在类上的泛型,类中静态方法无法使用,因为静态方法属于类级别,跟对象创建时机不一致。
3.3 注意堆污染
当一个持有泛型a的对象A,赋值给无泛型的对象B,再将B赋值给持有不同泛型的对象C,这时候取值会发生类型转换异常 : ClassCastException
如下代码:
public static void main(String[] args) {
List<String> strList = new ArrayList<>();
strList.add("a");
List<Integer> integerList = new ArrayList<>();
integerList.add(0);
List list = integerList;
List<String> stringList = list;
System.out.println(stringList.get(0));
}
运行结果:

image.png
4、拓展
4.1 类型擦除
泛型只在编译器期作用,运行期把类型擦除了。
示例代码:List<String> 对象如果想直接添加 Integer 类型的元素,会有一条红线提示编译不通过,但是通过反射在运行期间进行添加,却能添加成功。
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<String> strList = new ArrayList<>();
strList.add("a");
System.out.println("编译期"+strList.size());
//strList.add(123); //编译器无法通过编译
//使用反射进行运行期动态操作
Class<? extends List> aClass = strList.getClass();
Method add = aClass.getDeclaredMethod("add", Object.class);
add.invoke(strList,123);
System.out.println("运行期"+strList.size());
}
运行结果:

image.png
Process finished with exit code 0
4.2 桥接方法
泛型是JDK 1.5 后的方法,编译成class文件后会自动生成一个桥接方法(出入参都是Object),兼容以前版本。