泛型使得在定类、接口、方法时可以传递类型信息(类、接口)作为参数。
比起没有泛型的时期,使用泛型更方便于:
编译期间类型安全检查,编译期间的错误比起运行时错误更方便解决
避免了类型转换
cast
有助于抽象出针对同一类型的计算逻辑
generic algorithms
generic type and generic method
Java 中泛型使用<T>
符号申明在类、接口、方法处。
一般而言T
符号的取值参考有:
- E - Element (比如集合中使用)
- K - Key
- N - Number
- T - Type
- V - Value
- S,U,V etc. - 2nd, 3rd, 4th types
1 | class Box<T>{ |
Box 类需要使用一个泛型参数。是使用的时候需要申明具体的实参类型才行。
generic type
申明在类、接口处的泛型,在初始化类的时候,需要传递具体的参数类型。泛型类
1 | class Box<T>{ |
generic method
声明在方法处的泛型,在调用方法的时候,需要传递具体的参数类型。与 generic type 不一样的是,这个是方法自己特有的泛型信息。泛型方法
1 | class Utils{ |
generics Inheritance subtypes
Integer
是Number
类的子类,但是Box<Integer>
和Box<Number>
之间是没有继承关系。
泛型类或者接口是可以被extends
或者impements
。这样泛型类型之间就有用继承关系了。
ArrayList<String>
是List<String>
的子类型 subtype
List<String>
是ArrayList<String>
的父类型 supertype
bounded type parameters
泛型的赋值是任意类型的,但是也可以限定具体的类型。
1 | public <U extends Number> void inspect(U u){ |
inspect()
限定了只能用于Number
类型或者Number
类型的子类作为参数。
?
在泛型中是一个比较常用的符号,用来表示某一类类型,未知类型。通常将?
类型传递给申明处的泛型类型<T>
来达到限制类型边界作用。
U extends Number
以及? extends Number
晃眼一看比较类似。
前者是泛型在申明时,指定了泛型在初始化的边界信息。通常在泛型类或者泛型方法申明处使用。
后者是泛型在调用时,指定了能支持的实际参数类型。通常是在方法申明参数的时候使用。
限定泛型的边界有助于实现generic algorithms
1 | public static <T> int countGreaterThan(T[] anArray, T elem) { |
因为T
是任意类型的,限定一下T
的具体类型就可以实现泛型的比较了
1 | public interface Comparable<T> { |
upper bound wildcards
1 | public static double sumOfList(List<? extends Number> list) { |
sumOfList()
方法接受的参数可以List<Integer>
,List<Double>
, 以及List<Number>
都可以。
被extends
标记的变量只能提供提供元素get()
,是一个in
类型的变量。
lower bound wildcards
1 | public static void addNumbers(List<? super Integer> list) { |
addNumbers()
限定了支持的参数有List<Integer>
,List<Number>
,以及List<Object>
。
被super
关键字标记的变量只能保存数据set()
,是一个out
变量。
unbound wildcards
1 | public static void printList(List list) { double s = 0.0; for (Number n : list) s += n.doubleValue(); return s;} |
printList()
方法支持大于任何的List
对象,并没有限制边界
type ensure
泛型类型在编译后,被抹除掉了,使用到泛型的地方,如果明显的指定了泛型的边界信息泛型类型将会被替换成边界类型信息,否者就是Object类型。
泛型类被抹除泛型信息后就是raw type。下面的Node<T>
的raw tye 就是Node
generic type ensure
1 | public class Node<T> { |
泛型T
是没有指定边界的,所以Java 编译器或有Object
来代替它:
1 | public class Node { |
如果指定泛型边界
1 | public class Node<T extends Comparable<T>> { |
编译后:
1 | public class Node { |
generic method ensure
1 | public static <T> int count(T[] anArray, T elem) { |
T
没有指定边界,所以用Object
代替
1 | public static int count(Object[] anArray, Object elem) { |
T
指定了边界
1 | class Shape { /* ... */ } |
tags: [Java反射,构造器,Constructors]
categories: Java译文编译后
1 | public static void draw(Shape shape) { /* ... */ } |
tyepe ensure warning
由于泛型信息被抹除了,下面的结果是true
,被编译后两个List的class 信息都是Object,所以相等。
1 | new ArrayList().getClass() == new ArrayList().getClass() |
Restriction on generic
由于类型擦除,我们失去了获取形参T实际类型的能力,我们不能new T()、new T[]、List.class、instanceof List。