通常我们使用 Class
来描述数据类型,其实在 JDK
中有一个更通用类型接口 Type
,Type
是 JDK
中所有类型的公共父接口,Class
也是 Type
的其中一个实现类。
public interface Type {
default String getTypeName() {
return this.toString();
}
}
在没有泛型之前,Java
只有原始类型(raw type
),此时的类型都通过 Class
进行描述。
public final class Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
加入泛型之后,JDK
对类型进行了扩充,在 Class
之外添加了以下四种类型。
类型 | 描述 |
---|---|
ParameterizedType | 参数化类型,即常说的泛型,例如:List<String> 、Map<Integer, String> |
GenericArrayType | 泛型数组类型,例如:T[] |
TypeVariable | 类型变量类型,例如:List<T> 中的 T |
WildcardType | 通配符类型,并不是 JAVA 类型,而是泛型表达式,例如:? 、? super T 、? extends T |
ParameterizedType 的用法
ParameterizedType
表示参数化类型,所谓参数指的就是 <>
中的泛型。
public interface ParameterizedType extends Type {
// 获取 <> 内的泛型类型
Type[] getActualTypeArguments();
// 获取原始类型,如果泛型结构为 O<T>,返回 O
Type getRawType();
// 如果泛型结构为 O<T>.I<S>,返回外层的 O<T>
Type getOwnerType();
}
获取父类的泛型信息
在 Class
类中有一个 getGenericSuperclass()
方法,用于获取带泛型信息的父类,如果父类不带泛型,则等同于 getSuperclass()
方法。
创建一个不带泛型的父类并实现
public class GenericService {
}
public class UserService extends GenericService {
}
public class GenericTest {
public static void main(String[] args) {
Type genericSuperClass = UserService.class.getGenericSuperclass();
Class<? super UserService> superclass = UserService.class.getSuperclass();
System.out.println(genericSuperClass);
System.out.println(superclass);
System.out.println(genericSuperClass == superclass);
}
}
输出如下
class test.GenericService
class test.GenericService
true
可以看到 getGenericSuperclass
与 getSuperclass
返回的都是 Class
,而且是同一个 Class
。
接下来使用泛型,再次验证,这里需要两个类 UserRepository
与 User
,自行创建即可。
public class GenericService<T, M> {
}
public class UserService extends GenericService<UserRepository, User> {
}
再次运行,可以看到两者返回的对象已经不一样了,getGenericSuperclass
方法返回的是带了泛型信息的 ParameterizedType
。
test.GenericService<test.UserRepository, test.User>
class test.GenericService
false
通过 ParameterizedType
可以进一步获取到泛型
public class GenericTest {
public static void main(String[] args) {
Type genericSuperClass = UserService.class.getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) genericSuperClass;
// 获取原始类型 Class
displayType(parameterizedType.getRawType());
// 获取泛型
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type argument : actualTypeArguments) {
displayType(argument);
}
}
public static void displayType(Type type) {
System.out.println(type.getTypeName() + " --- " + type.getClass().getSimpleName());
}
}
输出结果
test.GenericService --- Class
test.UserRepository --- Class
test.User --- Class
获取接口的泛型信息
在 Class
类中还提供了一个 getGenericInterfaces()
方法,用于获取带泛型信息的接口。
创建两个接口,一个不带泛型,一个带泛型
public interface IA {
}
public interface IB<T, P extends Serializable> {
}
创建一个实现类
public class Impl implements IA, IB<UserRepository, User> {
}
获取接口的泛型
public class GenericTest {
public static void main(String[] args) {
Type[] genericInterfaces = Impl.class.getGenericInterfaces();
for (Type type : genericInterfaces) {
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
displayType(parameterizedType);
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type argument : actualTypeArguments) {
displayType(argument);
}
} else {
displayType(type);
}
System.out.println("-------------------------------");
}
}
public static void displayType(Type type) {
System.out.println(type.getTypeName() + " --- " + type.getClass().getSimpleName());
}
}
输出结果
test.IA --- Class
-------------------------------
test.IB<test.UserRepository, test.User> --- ParameterizedTypeImpl
test.UserRepository --- Class
test.User --- Class
-------------------------------
提供一个获取父类及接口泛型的工具类
public class ReflectUtils {
/**
* 获取父类指定位置的泛型类型
*/
public static Class<?> getSuperClassGenericType(Class<?> clazz, int index) {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
log.warn(String.format("Warn: %s's superclass not ParameterizedType", clazz.getSimpleName()));
return Object.class;
}
return indexOfGenericType(clazz, (ParameterizedType) genType, index);
}
/**
* 获取指定接口指定位置的泛型类型
*/
public static Class<?> getInterfaceGenericType(Class<?> clazz, Class<?> target, int index) {
for (Type genericInterface : clazz.getGenericInterfaces()) {
if (genericInterface instanceof ParameterizedType) {
if (((ParameterizedType) genericInterface).getRawType() == target) {
return indexOfGenericType(clazz, (ParameterizedType) genericInterface, index);
}
} else if (genericInterface == target) {
log.warn(String.format("Warn: %s's interface not ParameterizedType", clazz.getSimpleName()));
return Object.class;
}
}
return Object.class;
}
public static Class<?> indexOfGenericType(Class<?> clazz, ParameterizedType type, int index) {
Type[] params = type.getActualTypeArguments();
if (index >= params.length || index < 0) {
log.warn(String.format("Warn: Index: %s, Size of %s's Parameterized Type: %s .", index,
clazz.getSimpleName(), params.length));
return Object.class;
}
if (!(params[index] instanceof Class)) {
log.warn(String.format("Warn: %s not set the actual class on superclass generic parameter",
clazz.getSimpleName()));
return Object.class;
}
return (Class<?>) params[index];
}
}
获取字段的泛型类型
Field
类中提供了一个 getGenericType()
方法,用于获取带泛型信息的字段类型,如果不存在泛型信息,则该方法与 getType()
等效。
public class GenericTest {
private List<String> list;
private List unknownList;
private Map<String, Long> map;
private Map unknownMap;
private Map.Entry<String, Long> entry;
public static void main(String[] args) {
Field[] fields = GenericTest.class.getDeclaredFields();
for (Field f : fields) {
System.out.println(f.getName() + " is ParameterizedType: " + (f.getGenericType() instanceof ParameterizedType));
}
}
}
输出如下,可以看到,有没有泛型,不是看类声明有没有泛型,而是看变量声明时有没有带泛型。比如 unknownList
没有声明泛型,那么 getGenericType()
方法返回的就是 Class
,而不是 ParameterizedType
。
list is ParameterizedType: true
unknownList is ParameterizedType: false
map is ParameterizedType: true
unknownMap is ParameterizedType: false
entry is ParameterizedType: true
获取泛型变量的泛型信息
public class GenericTest {
private List<String> list;
private List unknownList;
private Map<String, Long> map;
private Map unknownMap;
private Map.Entry<String, Long> entry;
public static void main(String[] args) {
Field[] fields = GenericTest.class.getDeclaredFields();
for (Field f : fields) {
if (f.getGenericType() instanceof ParameterizedType) {
System.out.print(f.getName() + "<");
ParameterizedType genericType = (ParameterizedType) f.getGenericType();
Type[] typeArguments = genericType.getActualTypeArguments();
int i = 0;
for (Type argument : typeArguments) {
if (i++ > 0) {
System.out.print(",");
}
System.out.print(argument.getTypeName());
}
System.out.println(">");
}
}
}
}
输出如下
list<java.lang.String>
map<java.lang.String,java.lang.Long>
entry<java.lang.String,java.lang.Long>
这里也可以看一下 getOwnerType()
方法的用法
public class GenericTest {
private List<String> list;
private List unknownList;
private Map<String, Long> map;
private Map unknownMap;
private Map.Entry<String, Long> entry;
public static void main(String[] args) {
Field[] fields = GenericTest.class.getDeclaredFields();
for (Field f : fields) {
if (f.getGenericType() instanceof ParameterizedType) {
ParameterizedType genericType = (ParameterizedType) f.getGenericType();
System.out.println(f.getName() + " ownerType is " +
(genericType.getOwnerType() == null ? "null" : genericType.getOwnerType().getTypeName()));
}
}
}
}
输出如下,可以看到,当泛型结构为 O<T>.I<S>
类型时,调用 getOwnerType()
会返回外层的 O<T>
,否则返回空。
list ownerType is null
map ownerType is null
entry ownerType is java.util.Map
获取方法的泛型信息
public class GenericTest {
public static void main(String[] args) {
Method[] methods = GenericTest.class.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals("test")) {
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
if (genericParameterType instanceof ParameterizedType) {
System.out.println(genericParameterType.getTypeName());
}
}
}
}
}
public <T> T test(List<String> l1, List<ArrayList<String>> l2, List<T> l3,
List<? extends Number> l4, List<ArrayList<String>[]> l5, Map<Boolean, Integer> l6) {
return null;
}
}
输出如下
java.util.List<java.lang.String>
java.util.List<java.util.ArrayList<java.lang.String>>
java.util.List<T>
java.util.List<? extends java.lang.Number>
java.util.List<java.util.ArrayList<java.lang.String>[]>
java.util.Map<java.lang.Boolean, java.lang.Integer>
GenericArrayType 的用法
GenericArrayType
表示泛型数组
public interface GenericArrayType extends Type {
Type getGenericComponentType();
}
创建一个泛型类,包含一个泛型数组
public class Holder<T> {
private T[] arrayData;
public void test(List<String>[] listArray, T[] values) {}
}
public class GenericTest {
public static void main(String[] args) {
Field[] fields = Holder.class.getDeclaredFields();
for (Field field : fields) {
if (field.getGenericType() instanceof GenericArrayType) {
GenericArrayType genericType = (GenericArrayType) field.getGenericType();
System.out.println(field.getName() + " is " + genericType.getTypeName() +
" and componentType is " + genericType.getGenericComponentType().getTypeName());
}
}
}
}
输出如下
arrayData is T[] and componentType is T
TypeVariable 的用法
TypeVariable
表示泛型变量,只要泛型不是具体的类型,比如 <T>
、<E extends T>
都归类为泛型变量。
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
// 获取变量名
String getName();
// 获取原始类型
D getGenericDeclaration();
// 获取泛型的继承关系
Type[] getBounds();
AnnotatedType[] getAnnotatedBounds();
}
获取方法的返回参数
public class GenericTest {
public static void main(String[] args) {
Method[] methods = GenericTest.class.getDeclaredMethods();
Method method = Arrays.stream(methods)
.filter(v -> v.getName().equals("testTypeVariable"))
.findAny().get();
Type type = method.getGenericReturnType();
displayType(type);
TypeVariable typeVariable = (TypeVariable) type;
System.out.println(typeVariable.getGenericDeclaration());
displayType(typeVariable.getBounds()[0]);
}
public static void displayType(Type type) {
System.out.println(type.getTypeName() + " --- " + type.getClass().getSimpleName());
}
public <T extends User> T testTypeVariable() {
return null;
}
}
输出如下
T --- TypeVariableImpl
public test.User test.Test.testTypeVariable()
test.User --- Class
WildcardType 的用法
WildcardType
表示通配符,即 <?>
这种,接口包含两个方法
- getUpperBounds:通配符格式如
<? extends P>
这种,说明泛型类型继承自P
,getUpperBounds
方法可以获取到P
的类型 - getLowerBounds:通配符格式如
<? super C>
这种,说明泛型类型是C
的超类,getLowerBounds
方法可以获取到C
的类型
public interface WildcardType extends Type {
// 向上继承
Type[] getUpperBounds();
// 向下继承
Type[] getLowerBounds();
}
获取方法的参数,获取参数中定义的通配符信息
public class GenericTest {
public static void main(String[] args) {
Method[] methods = GenericTest.class.getDeclaredMethods();
Method method = Arrays.stream(methods)
.filter(v -> v.getName().equals("testWildcardType"))
.findAny().get();
Type[] types = method.getGenericParameterTypes();
int index = 0;
for (Type type : types) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type typeArgument = parameterizedType.getActualTypeArguments()[0];
System.out.println("参数" + ++index + "泛型类型:" + typeArgument.getClass().getSimpleName());
if (typeArgument instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) typeArgument;
for (Type upperType : wildcardType.getUpperBounds()) {
System.out.println(" upperType:" + upperType.getTypeName());
}
for (Type lowerType : wildcardType.getLowerBounds()) {
System.out.println(" lowerType:" + lowerType.getTypeName());
}
}
}
}
public <T> void testWildcardType(List<T> l1, List<?> l2, List<? extends T> l3, List<? super Integer> l4) {
}
}
输出如下
参数1泛型类型:TypeVariableImpl
参数2泛型类型:WildcardTypeImpl
upperType:java.lang.Object
参数3泛型类型:WildcardTypeImpl
upperType:T
参数4泛型类型:WildcardTypeImpl
upperType:java.lang.Object
lowerType:java.lang.Integer