泛型类和泛型方法
泛型类
public class Pair<T> { |
泛型方法
public Class ArrayAlg { |
泛型的类型限定
public static <T extends Comparable> T min(T[] a) { |
如果T需要多个类型限定: <T extends Comparable & Serializable>
类型擦除
- JVM没有”泛型类”这种类型, java代码被编译后生成的字节代码, 这个过程中所有的泛型类型要被替换, 原则:
- 有类型限定的, 替换为第一个限定类型,
T extends Comparable & Serializable被替换为Comparable - 无类型限定, 替换为Object,
T被替换为Object
- 有类型限定的, 替换为第一个限定类型,
对类型查询的影响
1. instanceof
Pair<String> s = new Pair<String>(); // 擦除后为 Pair<Object> s |
2. getClass()
Pair<String> s = new Pair<String>(); |
不能创建泛型类数组
// 试图创建泛型类型的数组会在编译期报错: |
原因是数组一旦创建会记住元素的类型, 当试图向数组中存储不同的类型时会报错, Pair<String>[]这样声明的泛型数组, 擦除后变为Pair<Object>[].
不能实例化泛型
不能使用像new T(), new T[N], T.class这样的表达式.
通配符<?>
无限定通配符
public static boolean Foo(List<?> list) { |
List<?>表示持有某种特定类型的List,但是不知道具体是哪种类型。那么我们可以向其中添加对象吗?当然不可以,因为并不知道实际是哪种类型,所以不能添加任何类型,这是不安全的。
上界通配符
? extends ClassType表示ClassType的任何子类
先看一段代码:List<? extends Fruit> list = new ArrayList<Apple>();
// Compile Error: can’t add any type of object:
// flist.add(new Apple());
// flist.add(new Fruit());
// flist.add(new Object());
// 只能向list里添加null
list.add(null);
// get是可以编译通过的
list.get(0);
做了泛型的向上转型 (List<? extends Fruit> flist = new ArrayList<Apple>()),那么我们也就失去了向这个List添加任何对象的能力,即使是Object也不行。
那么上界通配符有什么用呢?
public class GenericTest { |
List<? extends Fruit> list 表示一个List, 里面存储的类型是Fruit的派生类, 从list里get出来的类型至少是Fruit, 或者Fruit的派生类, 可以调用Fruit类的方法.
传递给GenericTest.func()的参数可以是List<Apple>, 也可以是List<Lemon>,
上界通配符<? extends Base>, 可以调用基类Base里定义的方法, 也可以get, 但是不可以set
下界通配符
? super Integer表示Integer的超类, 只能用于setter.
void setFirst(Pair<? super Integer>); |
限定符和泛型的一些问题…
泛型中无界通配符<?> 和<T>的区别?
<T>用在类或方法的定义里:public class ArrayList<T><?>通配符用在”调用”的地方, 通配符是拿来使用定义好的泛型的, 可以使用?的一般满足:- 方法定义里只使用Object的方法,跟
?类型无关; - 使用中不依赖于泛型, 最典型的是
Class<?> ...
- 方法定义里只使用Object的方法,跟
- 无限定通配符表示匹配任意类。
ArrayList<?>和ArrayList<Object>看上去有点类似,但实际却不一样。ArrayList<?>是任意ArrayList<T>的超类;List<Apple>是List<? extends Fruit>的子类(假设Apple继承自Fruit)ArrayList<Object>并不是ArrayList<T>的超类;