泛型
什么是泛型
-
使用
ArrayList
存储String
类型的缺点:- 需强制转换;
- 不方便,易出错;
-
泛型即定义一种模板来适应任意类型,如
ArrayList<T>
,然后在代码中为用到的类创建对应ArrayList<类型>
;ArrayList<String> strList = new ArrayList<String>(); strList.add("cunyu"); String str = strList.get(0);
-
向上转型:
ArrayList<T>
实现了List<T>
接口,可以向上转型为List<T>
;public class ArrayList<T> implements List<T>{ ... } List<String> list = new ArrayList<String>();
-
泛型的好处:使用时无需对类型进行强制转换,通过编译器对类型进行检查;
-
泛型的继承关系:
T
(即类型)不能变,如可以将ArrayList<Integer>
向上转型为List<Integer>
;
使用泛型
-
编译器能自动推断出泛型类型,因此下例两种写法等价;
List<String> list = new List<>(); List<String> list = new List<String>();
-
泛型接口:除了
ArrayList<T>
使用了泛型,还可以在接口中使用泛型,但在使用时必须实现这个接口;// 利用泛型接口进行字符串数组排序 import java.util.Arrays; public class Main{ public static void main(String[] args) throws Exception { String[] ss = new String[] {"Apple", "Huawei", "Xiaomi", "Vivo"}; Arrays.sort(ss); System.out.println(Arrays.toString(ss)); } }
-
不指定泛型参数类型是,编译器会发出警告,且只能将
<T>
视为Object
类型;
编写泛型
-
编写泛型类的步骤;
1. 按照某类型来编写类; 2. 标记所有特定类型; 3. 将特定类型替换为`T`,同时申明`<T>`;
public class Pair<T>{ private T first; private T last; public Pair(T first, T last){ this.first = first; this.last = last; } public T getFirst(){ return first; } public T getLast(){ return last; } }
-
注意编写泛型类是,泛型类型
<T>
不能用于静态方法;// 编译错误 public static Pair<T> create(T first, T last){ return new Pari<T>(first, last); }
-
同时定义多个泛型类型;
public class Pair<T, K> { private T first; private K last; public Pair(T first, K last) { this.first = first; this.last = last; } public T getFirst() { ... } public K getLast() { ... } }
擦拭法(Type Erasure)
- 定义
指虚拟机对泛型一无所知,所有工作均由编译器执行,Java
中的泛型实现方式即为擦拭法;
Java
使用擦拭法实现泛型的后果
- 编译器将类型
<T>
看做Object
; - 编译器会根据
<T>
实现安全的强制转型;
- 泛型的局限
-
<T>
不是基本类型;Pari<int> p = new Pair<>(1, 2); // 编译会出错
-
无法取得带泛型的
Class
;Pair<String>.class // 编译出错
-
无法判断带泛型的
Class
;x instanceof Pair<String>; // 编译出错
-
不能实例化
<T>
类型;T last = new T(); // 编译错误
- 泛型继承
public class IntPair extends Pair<Integer>{
// IntPair继承自Pair
...
}
Java
类型系统结构
extends通配符
- 使用
extends
统配负表示可以读,但是不能写;
使用类似<? extends Number>
通配符作为方法参数时表示:
- 方法内部可调用获取
Number
引用的方法,如Number n = obj.getFirst();
; - 方法内部无法调用传入
Number
引用的方法(null
除外),如obj.setFirst(Number n);
;
- 使用类似
<T extends Number>
定义泛型时表示:泛型类型限定为Number
及Number
的子类;