用简单明了的文字, 记录认知.
Java 泛型即"类型参数化", 定义时只声明类型参数,然后在使用时传入具体的类型。就像定义函数时的形参和实参关系,定义函数时只是定义了形参,在运行时才传递的实参。
泛型在编译阶段有效, 其实本质是一种语法糖.
1. 编译期进行类型安全检查.
// 没有使用泛型, lis 中可以随意添加
List list = new ArrayList();
list.add("hello world");
list.add(1);
list.add(new Object());
// 使用泛型, numbers 只能添加定义的类型, 否则在编译器报错
List<Number> numbers = new ArrayList<>();
numbers.add(new Integer(1));
numbers.add(new Double(1.0));
// numbers.add("hello world"); Required type:Number Provided:String
// numbers.add(new Object()); Required type:Number Provided:Object
2. 替代强制类型转换, 实现自动和隐式转换.
// 不使用泛型
List list = new ArrayList();
list.add("hello world");
Object o = list.get(0); //直接获取时为 Object
String s = (String) list.get(0); //强制类型转换
// 使用泛型, 自动完成类型转换
List<String> strList = new ArrayList<>();
String str = strList.get(0); //直接获取 String 类型
经过编译阶段, 所有的泛型信息都会被擦掉. 在生成的字节码中是不包含泛型中的类型信息的.
1. 运行时类对象不包含泛型信息
ArrayList<String> list1 = new ArrayList<String>();
list1.add("abc");
ArrayList<Integer> list2 = new ArrayList<Integer>();
list2.add(123);
// 结果为 true, 运行时泛型类型 Integer 和 String 都被擦除掉了 , 只剩下原始类型.
System.out.println(list1.getClass() == list2.getClass());
2. 反射调用, 可避开类型检查
ArrayList<Integer> list = new ArrayList<Integer>();
// 泛型类型为 Integer
list.add(1);
// list.add("hello world"); 编译时类型检查报错
// 通过反射, 运行时成功添加字符串
list.getClass().getMethod("add", Object.class).invoke(list, "hello world");
System.out.println(list.get(0)); //输出 0
System.out.println(list.get(1)); //输出 "hello world"
泛型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
1. 泛型类和接口
类和接口的定义中,使用参数化类型定义,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。
class 类名称 <泛型标识> {
private 泛型标识 var;
....
}
2. 泛型方法
方法定义中,使用参数化类型定义,被称为泛型方法。在调用方法的时候指明泛型的具体类型 。
<泛型标识> 泛型标识 methodName(泛型标识或其他类型 参数…){
…
}
本质上字符都可以作为通配符,没啥区别,只不过是编码时的一种约定俗成的东西。比如 T ,我们可以换成 A-Z 之间的任何一个 字母都可以,并不会影响程序的正常运行,但是如果换成其他的字母代替 T ,在可读性上可能会弱一些。
用来限制类型的上限, 使用具体类型必须是限定类型或限定类型的子类
<? extends 限定类型>
<T extends 限定类型>
用来限制类型的下限, 使用具体类型必须是限定类型或限定类型的父类
<? super 限定类型>
<T super 限定类型>
List<String> list = new ArrayList();
list.add("1");
list.add("2");
// list.add(1); 类型检查
...
// 自动类型转换
for(String s : list){
System.out.println(s);
}
// 定义一个泛型方法
public static <T extends Comparable> T min(T a, T b) {
if (a.compareTo(b) < 0) {
return a;
} else {
return b;
}
}
// 用于 Integer
int minInt = min(1, 2);
System.out.println(minInt);
// 用于 String
String minStr = min("a", "b");
System.out.println(minStr);