定义泛型
泛型用一套代码套用各种类型。与C++ template模板一样。
用<T>
表示泛型T。T换成任意字符串都行,比如<X>
。
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;
}
}
Pair<String> p = new Pair<String>("a", "b");
多类型泛型:
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() { ... }
}
Pair<String, Integer> p = new Pair<>("test", 123);
使用泛型
类使用泛型
List<String> list = new ArrayList<String>();
接口使用泛型
Arrays.sort(Object[])
可以对任意数组进行排序,但待排序的元素必须实现Comparable<T>
这个泛型接口:
public interface Comparable<T> {
/**
* 返回负数: 当前实例比参数o小
* 返回0: 当前实例与参数o相等
* 返回正数: 当前实例比参数o大
*/
int compareTo(T o);
}
例子
package oop_package.src.com.itranswarp.sample;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Person[] ps = new Person[] {
new Person("Bob", 61),
new Person("Alice", 88),
new Person("Lily", 75),
};
Arrays.sort(ps);
System.out.println(Arrays.toString(ps));
}
}
class Person implements Comparable<Person> {
String name;
int score;
Person(String name, int score) {
this.name = name;
this.score = score;
}
public int compareTo(Person other) {
return this.name.compareTo(other.name);
}
public String toString() {
return this.name + "," + this.score;
}
}
实现原理:擦拭法 Type Erasure
JVM将<T>
替换为Object处理,需要转型的时候,根据<T>
实现安全的强制转型:
public class Pair {
private Object first;
private Object last;
public Pair(Object first, Object last) {
this.first = first;
this.last = last;
}
public Object getFirst() {
return first;
}
public Object getLast() {
return last;
}
}
所以有了以下局限:
<T>
是Object,所以不能是基本类型:Pair<int> p = new Pair<>(1, 2); // compile error!
- 无法取得泛型的具体Class,无论T的类型是什么,getClass()返回同一个Class实例,因为编译后它们全部都是Pair
- 无法判断带泛型的类型,
if (p instanceof Pair<String>) {} // Compile error:
- 不能实例化
T
类型,因为new T()
都变成了new Object()
覆写泛型类的方法时,要避开继承自Object
的:
// Compile error
public class Pair<T> {
public boolean equals(T t) { //因为会被擦拭成 equals(Object t)
return this == t;
}
}
// right
public class Pair<T> {
public boolean same(T t) {
return this == t;
}
}
泛型继承
//父类指定过了具体类型,编译器就知道了,不用再视为Object了
public class IntPair extends Pair<Integer> {
}
IntPair ip = new IntPair(1, 2);
引入泛型后的Java类型系统结构
引入泛型后,Class不够用了,实际的类型系统结构如下:
┌────┐
│Type│
└────┘
▲
│
┌────────────┬────────┴─────────┬───────────────┐
│ │ │ │
┌─────┐┌─────────────────┐┌────────────────┐┌────────────┐
│Class││ParameterizedType││GenericArrayType││WildcardType│
└─────┘└─────────────────┘└────────────────┘└────────────┘
extends通配符
使用extends通配符表示可以读,不能写:
int sumOfList(List<? extends Integer> list) {
int sum = 0;
for (int i=0; i<list.size(); i++) {
Integer n = list.get(i);
sum = sum + n;
}
return sum;
}
使用类似<T extends Number>
定义泛型类时表示:泛型类型限定为Number以及Number的子类:
public class Pair<T extends Number> { ... }
super通配符
//TODO
泛型和反射
//TODO