泛型类型:泛型类型是在类型上参数化的泛型类或接口。
泛型使用场景:
• 编译时强类型检查
• 避免类型强转
• 实现通用算法
泛型被引入到 Java 语言中,以便在编译时提供更严格的类型检查并支持泛型编程。类型擦除确保不会为参数化类型创建新类;因此,泛型不会产生运行时开销。为了实现泛型,编译器将类型擦除应用于:
• 将泛型类型中的所有类型参数替换为其边界,如果类型参数是无边界的,则将其替换为“Object”。因此,生成的字节码只包含普通类、接口和方法
• 必要时插入类型转换以保持类型安全
• 生成桥方法以保留扩展泛型类型中的多态性
List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
// 1.将有泛型约束的list赋值给没有泛型约束的一个新集合
List temp = list;
// 2.此时temp可以添加任意对象到集合中
temp.add(2);
// 3.使用temp获取集合中的元素可以正常获取,没有泛型约束意味着参数类型无边界
// 则将其泛型替换为Object类型
System.out.println(temp.get(2));
// 4.使用list获取集合中的元素会抛出类型转换异常,因为list集合的泛型为String类型
// 在获取元素时,会进行一次类型转换将元素转为String类型,所以会报错
System.out.println(list.get(2));
Java泛型 更多的是编译期间给我们做的强类型约束,而运行时JVM不会关心泛型的类型。
Java 5 类型接口 - java.lang.reflect.Type:
派生类或接口 | 说明 |
---|---|
java.lang.Class | Java 类 API,如 java.lang.String |
java.lang.reflect.GenericArrayType | 泛型数组类型 |
java.lang.reflect.ParameterizedType | 泛型参数类型 |
java.lang.reflect.TypeVariable | 泛型类型变量,如 Collection 中的 E |
java.lang.reflect.WildcardType | 泛型通配类型 |
Java 泛型反射 API:
类型 | API |
---|---|
泛型信息(Generics Info) | java.lang.Class#getGenericInfo() |
泛型参数(Parameters) | java.lang.reflect.ParameterizedType |
泛型父类(Super Classes) | java.lang.Class#getGenericSuperclass() |
泛型接口(Interfaces) | java.lang.Class#getGenericInterfaces() |
泛型声明(Generics Declaration) | java.lang.reflect.GenericDeclaration |
我们看一下Class类,实现了Type接口。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
Type接口在JDK1.8之前,是一个空的接口,表示Java编程语言中所有类型的公共超接口。这些类型包括原始类型、参数化类型、数组类型、类型变量和基本类型。1.8之后增加了一个方法:
public interface Type {
default String getTypeName() {
return toString();
}
}
Class中有着很多对泛型操作的方法,获取的泛型类型就是Type类型。
// 基本类型 primitive types : int long float
Class intClass = int.class;
// 数组类型 array types : int[],Object[]
Class objectArrayClass = Object[].class;
// 原始类型 raw types : java.lang.String
Class rawClass = String.class;
// 泛型参数类型 parameterized type
ParameterizedType parameterizedType = (ParameterizedType) ArrayList.class.getGenericSuperclass();
// parameterizedType.getRawType() = java.util.AbstractList
// 泛型类型变量 Type Variable:
System.out.println(parameterizedType.toString()); // java.util.AbstractList
//
Type[] typeVariables = parameterizedType.getActualTypeArguments();
Stream.of(typeVariables)
.map(TypeVariable.class::cast) // Type -> TypeVariable
.forEach(System.out::println);
java反射获取泛型此处只做简单实例。
更多java泛型相关基础请自行学习,本文主要介绍Spring对泛型的处理。
核心 API - org.springframework.core.GenericTypeResolver
版本支持:[2.5.2 , )
处理类型相关(Type)相关方法
• resolveReturnType
• resolveType
处理泛型参数类型(ParameterizedType)相关方法
• resolveReturnTypeArgument
• resolveTypeArgument
• resolveTypeArguments
处理泛型类型变量(TypeVariable)相关方法
• getTypeVariableMap
import org.springframework.core.GenericTypeResolver;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* {@link GenericTypeResolver} 示例
*/
public class GenericTypeResolverDemo {
public static void main(String[] args) throws NoSuchMethodException {
// String 是 Comparable 具体化
displayReturnTypeGenericInfo(GenericTypeResolverDemo.class, Comparable.class, "getString");
// ArrayList
displayReturnTypeGenericInfo(GenericTypeResolverDemo.class, List.class, "getList");
// StringList 也是 List 泛型参数类型的具体化
displayReturnTypeGenericInfo(GenericTypeResolverDemo.class, List.class, "getStringList");
// 泛型参数类型的具体化 具备 ParameterizedType 返回,否则 null
// TypeVariable
Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(StringList.class);
// {E=class java.lang.String, E=class java.lang.String, T=class java.lang.String, E=class java.lang.String, E=class java.lang.String, E=class java.lang.String}
// StringList 继承父类包括父接口列表,所以会有多个 E,并且同时指向了 java.lang.String 类对象
// typeVariableTypeMap 包含了所有接口中的 TypeVariable 和 Type 的映射,简单地说,E 和 T 这类的,代表泛型参数,Type 代表具体的类型。
System.out.println(typeVariableMap);
}
public static StringList getStringList() {
return null;
}
public static ArrayList<Object> getList() { // 泛型参数类型具体化
return null;
}
public static String getString() {
return null;
}
/**
*
* @param containingClass Class类型
* @param genericIfc 泛型接口类型
* @param methodName 方法名
* @param argumentTypes 方法参数
* @throws NoSuchMethodException
*/
private static void displayReturnTypeGenericInfo(Class<?> containingClass, Class<?> genericIfc, String methodName, Class... argumentTypes) throws NoSuchMethodException {
// 根据方法名获取Method
Method method = containingClass.getMethod(methodName, argumentTypes);
// 声明类 GenericTypeResolverDemo.class 获取返回值类型
Class<?> returnType = GenericTypeResolver.resolveReturnType(method, containingClass);
// 常规类作为方法返回值
System.out.printf("GenericTypeResolver.resolveReturnType(%s,%s) = %s\n", methodName, containingClass.getSimpleName(), returnType);
// 常规类型不具备泛型参数类型 List 获取返回值类型的泛型
Class<?> returnTypeArgument = GenericTypeResolver.resolveReturnTypeArgument(method, genericIfc);
System.out.printf("GenericTypeResolver.resolveReturnTypeArgument(%s,%s) = %s\n", methodName, containingClass.getSimpleName(), returnTypeArgument);
}
}
class StringList extends ArrayList<String> { // 泛型参数具体化(字节码有记录)
}
核心 API - org.springframework.core.GenericCollectionTypeResolver
版本支持:[2.0 , 4.3] (新版本的spring已经不用了)
替换实现:org.springframework.core.ResolvableType
处理 Collection 相关
• getCollection*Type
处理 Map 相关
• getMapKeyType
• getMapValueType
import org.springframework.core.GenericCollectionTypeResolver;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* {@link GenericCollectionTypeResolver} 示例
*/
public class GenericCollectionTypeResolverDemo {
private static StringList stringList;
private static List<String> strings;
public static void main(String[] args) throws Exception {
// StringList extends ArrayList 具体化
// getCollectionType 返回具体化泛型参数类型集合的成员类型 = String
System.out.println(GenericCollectionTypeResolver.getCollectionType(StringList.class));
System.out.println(GenericCollectionTypeResolver.getCollectionType(ArrayList.class));
// 获取字段
Field field = GenericCollectionTypeResolverDemo.class.getDeclaredField("stringList");
System.out.println(GenericCollectionTypeResolver.getCollectionFieldType(field));
field = GenericCollectionTypeResolverDemo.class.getDeclaredField("strings");
System.out.println(GenericCollectionTypeResolver.getCollectionFieldType(field));
}
}
核心 API - org.springframework.core.MethodParameter
起始版本:[2.0 , )
元信息(部分)
• 关联的方法 - Method
• 关联的构造器 - Constructor
• 构造器或方法参数索引 - parameterIndex
• 构造器或方法参数类型 - parameterType
• 构造器或方法参数泛型类型 - genericParameterType
• 构造器或方法参数参数名称 - parameterName
• 所在的类 - containingClass
核心 API - org.springframework.core.ResolvableType
• 起始版本:[4.0 , )
• 扮演角色:GenericTypeResolver 和 GenericCollectionTypeResolver 替代者
• 工厂方法:for* 方法
• 转换方法:as* 方法
• 处理方法:resolve* 方法
ResolvableType封装Java类型,提供对超类型、接口和泛型参数的访问,以及最终解析为类的能力。
Doc中有一个实例:
ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap"));
t.getSuperType(); // AbstractMap>
t.asMap(); // Map>
t.getGeneric(0).resolve(); // Integer
t.getGeneric(1).resolve(); // List
t.getGeneric(1); // List
t.resolveGeneric(1, 0); // String
public class ResolvableTypeDemo {
public static void main(String[] args) {
// 工厂创建
// StringList <- ArrayList <- AbstractList <- List <- Collection
ResolvableType resolvableType = ResolvableType.forClass(StringList.class);
resolvableType.getSuperType(); // ArrayList
resolvableType.getSuperType().getSuperType(); // AbstractList
System.out.println(resolvableType.asCollection().resolve()); // 获取 Raw Type(interface java.util.Collection)
System.out.println(resolvableType.asCollection().resolveGeneric(0)); // 获取泛型参数类型(class java.lang.String)
}
}
class StringList extends ArrayList<String> {
}
局限一:ResolvableType 无法处理泛型擦写
局限二:ResolvableType 无法处理非具体化的 ParameterizedType
简化 Java 5 Type API 开发,屏蔽复杂 API 的运用,如 ParameterizedType
不变性设计(Immutability)
Fluent API 设计(Builder 模式),链式(流式)编程
极客时间-《小马哥讲 Spring 核心编程思想》