定义
在编译时期就对元素的类型进行检查,一旦发现不匹配就编译失败。在编译时泛型就被擦除了,所以无法在运行时得知其类型参数的类型。通过泛型可以定义类型安全的数据结构(类型安全),而无须使用实际的数据类型(可扩展),这能够显著提高性能并得到更高质量的代码(高性能),因为可以重用数据处理算法,而无须复制类型特定的代码(可重用)。
泛型可以定义在类,接口,方法上
- 定义时尖括号里的每个元素都代指一种未知类型
- 尖括号的位置非常讲究,必须在类名之后或者方法返回值之前
- 泛型在定义处只具备Object方法的能力
- 基本数据类型不能作为泛型参数
// 泛型接口
public interface Genericity<T> {
T test();
}
public class Son implements Genericity<Integer> {
@Override
public Integer test() {
return null;
}
}
// 泛型类 在编译时是无法知道K和V具体是什么类型,只有在运行时才会真正根据类型来构造和分配内存。
@Data
public class Container<K, V> {
private K key;
private V value;
public Container(K key, V value) {
this.key = key;
this.value = value;
}
// 这里不能用static修饰 静态方法无法访问类上定义的泛型。
public K test(V v){
return null;
}
// String不等于java.lang.String,只是一个自定义的泛型类型
public static <String> String test2(String str){
return str;
}
public static void main(String[] args) {
// 这里如果传入的是Integer类型,编译不会报错,运行会报ClassCastException
Container<String, String> container = new Container(1, 2);
System.out.println(container.getKey());
System.out.println(container.getValue());
}
}
泛型的限定
<? extends E>
泛型上限 接收E或者E的子类,一般在存储元素时使用上限,取值时用E来接收,不会存在类型安全问题
public static void printCollection(List<? extends Number> list){
Number number = list.get(0);
}
<? super E>
泛型下限 接收E或者E的父类,从集合取值时可以用E或者E的父类接收
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
泛型擦除
List<String> list = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list.getClass() == list2.getClass()); // true
泛型擦除带来的问题
- 不能使用泛型来重载方法
- 2.不能catch同一个异常的不同泛型实例
- 3.不同泛型类的静态变量是共享的
- 4.泛型间不存在继承关系,不能使用List 来接收List类型的参数