一、泛型的好处
简单的说,
- 泛型编程,意味着编写的代码可以被很多不同类型的对象所重用。比如ArrayList类使用泛型可以聚合Integer和String,而不是单独编写个ArrayList。有种多态的感觉。
- 提供错误检查机制,如ArrayList<String> list = new ArrayList<>();list就不可以添加非String类型的变量,java编译器就会错误检测。再者不需要提供强制类型装换,如String s = list.get(0);
二、类型变量命名约定
- T : 普通的泛型
- K : Key的简写,用于键值对的键
- V : Value的简写,用于键值对的值
三、泛型体系

(1)、Type接口
官方的解释:Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。
/**
* Type is the common superinterface for all types in the Java
* programming language. These include raw types, parameterized types,
* array types, type variables and primitive types.
*
* @since 1.5
*/
public interface Type {
/**
* Returns a string describing this type, including information
* about any type parameters.
*
* @implSpec The default implementation calls {@code toString}.
*
* @return a string describing this type
* @since 1.8
*/
default String getTypeName() {
return toString();
}
}
从图中可以看出Type的四大子接口,它们分别代表不同的类型:
- 原始类型(Class) : 对应的就是普通的类,注解等。如String.getClass()就是一个原始类型。
- 参数化类型(ParameterizedTypes):是整个泛型,如List<T> list;
- 类型变量(TypeVariable) : 如List<T> list 中的T
- 数组类型(GenericArrayType) :并不是普通的数组String[] 、byte[],而是带有泛型的数组,即T[]
- 基本类型 :基本类型,即int,float,double等。
- 通配符类型(WildcardType):List<?> 带有?的
泛型多是在框架中应用比较多,如Retrofit框架中的源码,该方法的大体意思就像是获取List<String>中的最外层的List类型。
static Class<?> getRawType(Type type) {
if (type == null) throw new NullPointerException("type == null");
if (type instanceof Class<?>) {
// Type is a normal class.
return (Class<?>) type;
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// I'm not exactly sure why getRawType() returns Type instead of Class. Neal isn't either but
// suspects some pathological case related to nested classes exists.
Type rawType = parameterizedType.getRawType();
if (!(rawType instanceof Class)) throw new IllegalArgumentException();
return (Class<?>) rawType;
}
if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
return Array.newInstance(getRawType(componentType), 0).getClass();
}
if (type instanceof TypeVariable) {
// We could use the variable's bounds, but that won't work if there are multiple. Having a raw
// type that's more general than necessary is okay.
return Object.class;
}
if (type instanceof WildcardType) {
return getRawType(((WildcardType) type).getUpperBounds()[0]);
}
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
+ "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName());
}
(2)、ParameterizedType接口
ParameterizedType 表示参数化类型,也就是泛型,如 Collection<String>。
如:
- Map<String, Person> map;
- Set<String> set1;
- Class<?> clz;
- Holder<String> holder;
- List<String> list;
ParameterizedType 接口提供了三个方法:
- Type[] getActualTypeArguments();
- Type getRawType();
- Type getOwnerType();
前两个方法比较常见,以Map<String, Person> map为例,getActualTypeArguments()获取的是String和Person类型的集合。getRawType()是获取到Map类型。
public class ParameterizedTest<T> {
// map对象
public Map<T,Integer> map;
public static void main(String[] args) throws Exception{
// 通过反射解析map对象
Field field = ParameterizedTest.class.getDeclaredField("map");
Type type =field.getGenericType();
// 是ParameterizedType类型
if (type instanceof ParameterizedType) {
// 1
Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
for (Type t : typeArguments) {
// 参数是TypeVariable
if (t instanceof TypeVariable) { // T 是 TypeVariable类型
System.out.println("TypeVariable: "+((TypeVariable) t).getName());
} else if (t instanceof Class<?>) { // Integer是Class<?> 原始类型
System.out.println("Class<?>: "+t);
}
}
// 2、
Type rawType = ((ParameterizedType) type).getRawType();
System.out.println("ParameterizedType: "+rawType);
}
}
}
结果:
TypeVariable: T
Class<?>: class java.lang.Integer
ParameterizedType: interface java.util.Map
(3)、TypeVariable接口
类型变量,例如:T、K、V等变量。TypeVariable代表着泛型中的变量,而ParameterizedType则代表整个泛型。
接口方法:
- Type[] getBounds(); // 得到上限的泛型
- D getGenericDeclaration(); // 获取声明该类型变量实体(是Class, Constructor, Method)
- String getName(); // 获取名字
public class TypeVariableTest<T> {
public static void main(String[] args) {
// 得到T
TypeVariable<?>[] typeParameters = TypeVariableTest.class.getTypeParameters();
for (TypeVariable type : typeParameters) {
System.out.println(type.getGenericDeclaration()); // 查看是哪里申明的
System.out.println(type.getName());
System.out.println();
Type[] boundTypes = type.getBounds();
for (Type boundType : boundTypes) {
System.out.println(boundType);
}
}
}
}
结果:
class JavaFinal.TypeVariableTest
T
class java.lang.Object
从D getGenericDeclaration()来看,可以在哪些地方声明泛型T了?
需要了解到GenericDeclaration这个接口,这是个声明泛型的接口

由结构可以看出,一共有三个地方可以声明泛型。
- 类 : TypeVariableTest<T>
- 方法 : <T> void print(T t)
- 构造方法: public <T> TypeVariableTest()
(4)、GenericArrayType接口
泛型数组。 它的组成元素是ParameterizedType或TypeVariable 类型。
接口方法:
- Type getGenericComponentType(); // 返回泛型数组中元素的Type类型,即T[] 中的T(TypeVariableImpl)
下列是几个GenericArrayType泛型例子:
// 属于 GenericArrayType
List<String>[] pTypeArray;
// 属于 GenericArrayType
T[] vTypeArray;
// 不属于 GenericArrayType
List<String> list;
// 不属于 GenericArrayType
String[] strings;
// 不属于 GenericArrayType
Person[] ints;
Retrofit中的例子:
if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
return Array.newInstance(getRawType(componentType), 0).getClass();
}
(5)、WildcardType
通配符泛型。这个一般不太常使用。只是获取通配符的上限泛型处理。
if (type instanceof WildcardType) {
return getRawType(((WildcardType) type).getUpperBounds()[0]);
}
网友评论