Written by
daweibayu
on
on
泛型详解
目的
个人认为最核心的目的就是“少些代码”,将共用逻辑抽象出来,形成“模版”。只不过不同语言、不同平台实现方式不一样、名称不一样。
## Java 泛型
### 示例
class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
public void genericsTest() {
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
System.out.println(stringBox.getItem());
Box<Integer> integerBox = new Box<>();
integerBox.setItem(123);
System.out.println(integerBox.getItem());
}
### 前因
Java 泛型是在 JDK 5 中引入的新特
### 编译期
编译期做代码(类型)检查
### 运行期
在运行时自动进行类型转换
类型擦除
编译时将泛型类型替换为它们的限定类型,示例代码如下:
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
如 T 无限定,则编译后的代码大概如下(即限定为 Object):
public class Box {
private Object item;
public void setItem(Object item) {
this.item = item;
}
public Object getItem() {
return item;
}
}
class Generics {}
public class Box<T extends Generics> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
如 T 有限定,则编译后的限定为父类(即示例中的 Generics):
public class Box {
private Generics item;
public void setItem(Generics item) {
this.item = item;
}
public Generics getItem() {
return item;
}
}
public class Box<T> {}
时至今日,类似 `List list = new ArrayList<>();` 的代码仍然是可以通过编译的
如 ArrayList 源码:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
...
transient Object[] elementData; // non-private to simplify nested class access
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
...
}
Java 范型的问题
- 类型擦除导致类型丢失
- Java不允许直接创建泛型类型的数组,如 new T[] 或 new List
[] - 不能使用基本类型作为泛型参数
- 不能使用 instanceof 检查泛型类型
- 不能在静态上下文中使用泛型类型,泛型类的静态成员不能使用泛型类型,因为泛型类型在类加载时并不可用。
- 受限的类型推断
- 泛型不能用于异常类
以上问题都是由于泛型擦除引发的,上述问题在 C++ 中并不存在。
super
public class MyClass<? super T> { } // 这会导致编译错误
public class MyBox<T> {
// 使用下界通配符的示例方法
public void addItems(List<? super T> list, T item) {
list.add(item); // 允许添加 T 或其子类
}
}
该代码编译后大概为:
public class MyBox {
// 由于泛型擦除,addItems 方法不再有 T 的类型信息
public void addItems(List list, Object item) {
list.add(item); // 由于类型擦除,参数类型变为 Object
}
}
## Koltin 泛型
## C++ 泛型
C++ 的模板在编译时为每种具体类型生成对应的代码,这种机制称为“模板实例化”
## C# 泛型
C# 跟 Java 是一样的,在最初的版本并不支持,在 C# version 2.0