为什么需要泛型
假设我们在2000年,那时候是没有泛型的,如何实现类型安全呢?答案是没办法,我们可以在一个 List
中随心所欲的添加不同类型的对象。如果一定要实现一个只能放String
类型的List
怎么办?只能用如下的代码。如果还需要一个只能Integer
类型的呢?我们需要复制好多次,才能实现全部的需求。
class StringListDecorator {
List list = new ArrayList();
void add(String s) {
list.add(s);
}
int size() {
return list.size();
}
String get(int i) {
return (String) list.get(i);
}
}
有了泛型后,一切都简单了。泛型的好处:1.安全 2.方便。
List<String> list = new ArrayList<>();
泛型的擦除
- 引入泛型后,为了保证向后兼容性,有两条路可以选择:1.擦除(Java的选择) 2.搞一套全新的API(C#的选择)。为了验证Java是类型擦除的,我们写了如下的代码:
public class Main {
public static void main(String[] args) {
String[] strings = new String[0];
new ArrayList();
}
}
使用ASMPlugin
插件去看字节码,我们可以清楚的看到,L0:数组确实是有类型String
的。而L1:ArrayList
的类型却被擦除了。那为什么我们往带String
泛型的List
中插入Integer
会报错呢?这只是编译器报错,Java的泛型是假泛型,是编译期的泛型,泛型信息在运⾏期完全不保留。所以说我们只要绕过编译器的检查,一切泛型都没有了,运行时是不会去检查的。
public class com/github/lazyben/Main {
// .......
public static main([Ljava/lang/String;)V
L0
LINENUMBER 8 L0
ICONST_0
ANEWARRAY java/lang/String
ASTORE 1
L1
LINENUMBER 9 L1
NEW java/util/ArrayList
DUP
INVOKESPECIAL java/util/ArrayList.<init> ()V
ASTORE 2
// .......
}
- 我们知道
String
是Object
的子类,String[]
是Object[]
的子类。但List<String>
并不是List<Object>
的⼦类型。
泛型的绑定
看一个简单的例子,我们可以做一个泛型的绑定以简化代码。
public class Main {
public int max(int a, int b) {
return a > b ? a : b;
}
public double max(double a, double b) {
return a > b ? a : b;
}
public long max(long a, long b) {
return a > b ? a : b;
}
}
声明<T extends Comparable>
表示T
一定继承了Comparable
接口,JVM会根据你传进来的参数做泛型的绑定。extends
要求泛型是某种类型及其⼦类型。
public <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
再来看一个关于super
的例子,以Collections.sort
为例:
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
sort的第二个参数接受一个Comparator
,他的泛型必须是T
及其父类,由此Comparator<Cat>
和Comparator<Animal>
都是可以的。 super
要求泛型是某种类型及其⽗类型。
public class Main {
public static void main(String[] args) {
final ArrayList<Cat> cats = new ArrayList<>();
Collections.sort(cats, new CatComparator());
Collections.sort(cats, new AnimalComparator());
}
static class CatComparator implements Comparator<Cat> {
@Override
public int compare(Cat o1, Cat o2) {
return 0;
}
}
static class AnimalComparator implements Comparator<Animal> {
@Override
public int compare(Animal o1, Animal o2) {
return 0;
}
}
}
网友评论