使用泛型可以处理多种类型的数据,增加了代码的灵活性。同时,数据类型的确定被推迟到编译阶段,因此编译阶段就可以完成检查,提前发现错误。本文通过例子来说明泛型的使用。
泛型简单使用
元组
元组:将一组对象打包放在了单一对象中,有点像java bean, 使用泛型可以很容易的构造多元元组出来。
二元组
public class TwoTuple<A,B> {
public final A a;
public final B b;
public TwoTuple(A a, B b) {
this.a = a;
this.b = b;
}
}
三元组
public class ThreeTuple<A, B, C> extends TwoTuple<A, B>{
public final C c;
public ThreeTuple<A a, B b, C c) {
super(a, b);
this.c = c
}
}
创建一个栈
public class LinkedStack<T> {
private Node<T> head;
class Node<T>{
T element;
Node<T> next;
}
public void push(T t) {
Node<T> node = new Node<>();
node.element = t;
node.next = head;
head = node;
}
public T pop() {
if (head != null) {
Node<T> node = head;
head = node.next;
return node.element;
} else
return null;
}
public static void main(String[] args) {
LinkedStack<String> stack = new LinkedStack<String>();
stack.push("aa");
stack.push("bbb");
System.out.println(stack.pop());
}
}
类型推断
//正常写法
Map<String, String> map = new HashMap<String, String>();
//类型推断
Map<String, String> map = new HashMap<>();
类型推断只对赋值操作有校,编译器会自动推断出容器中存储的具体类型。
泛型擦除
擦除例子
public static void main(String[] args) {
Class c1 = new ArrayList<Integer>().getClass();
Class c2 = new ArrayList<String>().getClass();
System.out.println(c1 == c2);
}
上面的代码输出结果为true, ArrayList< Integer >和ArrayList< String>会被认为是同一种类型。这看起来很奇怪,如果是同一种类型,那么其行为是一致,但事实上我们不能把一个字符串放入ArrayList< Integer >中。这是因为在使用泛型时,任何具体类型信息都会被擦除,你唯一知道的是你在使用一个对象。因此List<Stirng>
和List<String>
在运行时事实上都是原生类型List。
泛型的擦除是将具体类型信息擦除成原始类型信息,如何实现这一操作请参考连接
擦除补偿
由于擦除将类型信息抹掉了,但在实际开发中又需要根据类型进行不同操作,如下所示:
public class Erased<T> {
private final int SIZE = 100;
public static void f(Object arg) {
if (arg instanceof T) {} // Compile Error
T var = new T(); // Compile Error
T[] array = new T[SIZE]; // Compile Error
T[] array2 = (T) new Oject[SIZE]; // Unchecked warning
}
}
由于擦除,我们获取不同T的任何信息,因此也不能基于T进行相关的类型操作了。那怎么做呢,可以使用Class对象进行处理。
public class Erased<T> {
private final int SIZE = 100;
private final Class<T> kind;
public Erased(Class<T> kind) {
this.kind = kind;
}
public void f(Object arg) {
System.out.println(kind.isInstance(arg));
try {
T var = kind.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}