泛型类和泛型方法
泛型类
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>
的超类;