Better

业精于勤荒于嬉

Java反射9-泛型

Better's Avatar 2017-02-26 Java译文

  1. 1. 泛型的大体规则
  2. 2. 泛型方法的返回类型
  3. 3. 泛型方法参数的类型
  4. 4. 泛型成员变量的泛型
  • The Generics Reflection Rule of Thumb
  • Generic Method Return Types
  • Generic Method Parameter Types
  • Generic Field Types

我经常在一些文章或者论坛里面读到Java泛型在编译的时候已经被抹掉了,所以在运行时你不能获取到Java泛型。这完全是不对的。在少数情况下,可以在运行时访问泛型信息。这些情况实际上涵盖了我们对Java泛型信息的几个需求。本文将解释这些情况。

泛型的大体规则

以下两种情形会使用到泛型:

  1. 将类/接口声明为可参数化。
  2. 使用可参数化的类。

当你创建一个类或者接口的时候,你看申明它可以参数化。java.util.List就是这种情况。比如用java.util.List你可以创建一个String的列表,而不是只能创建Object类型的列表。
java.util.List这种使用泛型的的情形在程序运行的时候是没有办法去获取泛型到底被参数成了什么类型。这是合理的,因为泛型能被参数化为当前程序的所有类型。但是在程序运行时候,当你检查使用了泛型的方法或者作用域时,你是能够获取到泛型到底被那种数据参数化了。简而言之:
在运行时你是不能直接获取到泛型到底被那种数据参数化了,但是却可以通过使用泛型的方法和作用域来获取泛型的参数类型。或者说它有具体的参数化类型。接下来的几节将了解这些情况。

泛型方法的返回类型

若果你获取到了java.lang.reflect.Method对象,是能够去获取到方法的返回类型的(注:泛型的类型的参数类型)。这种方式是不能获取到所有方法的泛型参数类型,但是却可以获取到类中定义的使用了泛型的成员变量类型。你可以阅读’Java反射-方法’来了解怎么获取Method对象。下面这个例子讲述了类中的一个方法的返回类型包含泛型:

1
2
3
4
5
6
7
8
public class MyClass {

protected List<String> stringList = ...;

public List<String> getStringList(){
return this.stringList;
}
}

在MyClass类中是能够获取到getStringList()方法返回的泛型数据类型的。或者说,是能够获取到getStringList()方法返回了一个String类型的List而不是只能知道返回了一个List。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
Method method = MyClass.class.getMethod("getStringList", null);

Type returnType = method.getGenericReturnType();

if(returnType instanceof ParameterizedType){
ParameterizedType type = (ParameterizedType) returnType;
Type[] typeArguments = type.getActualTypeArguments();
for(Type typeArgument : typeArguments){
Class typeArgClass = (Class) typeArgument;
System.out.println("typeArgClass = " + typeArgClass);
}
}

上面的代码片段将输出typeArgClass = java.lang.String。Type[]数组typeArguments将包含一个元素–一个代表实现了Type接口的java.lang.String类的对象。类实现类型接口。

泛型方法参数的类型

你要可以放过Java反射获取带有泛型的参数的泛型类型。下面的例子中类中有个方法的参数是一个可参数化的List:

1
2
3
4
5
6
7
public class MyClass {
protected List<String> stringList = ...;

public void setStringList(List<String> list){
this.stringList = list;
}
}

你可以获取到泛型参数的泛型类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
method = Myclass.class.getMethod("setStringList", List.class);

Type[] genericParameterTypes = method.getGenericParameterTypes();

for(Type genericParameterType : genericParameterTypes){
if(genericParameterType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericParameterType;
Type[] parameterArgTypes = aType.getActualTypeArguments();
for(Type parameterArgType : parameterArgTypes){
Class parameterArgClass = (Class) parameterArgType;
System.out.println("parameterArgClass = " + parameterArgClass);
}
}
}

代码将输出parameterArgType = java.lang.String。这Type[]数组parameterArgTypes将包含一个元素–一个代表实现了Type接口的java.lang.String类的对象。类实现类型接口。

泛型成员变量的泛型

获取public的成员变量的泛型也是可以的。成员变量对象是类的成员-静态的或者实例变量。你可以阅读‘Java反射-成员变量’来了解怎样获取成员变量的对象。下面的例子是前面的例子,类中有一个叫做stringList的对象:

1
2
3
public class MyClass {
public List<String> stringList = ...;
}
1
2
3
4
5
6
7
8
9
10
11
12
Field field = MyClass.class.getField("stringList");

Type genericFieldType = field.getGenericType();

if(genericFieldType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = aType.getActualTypeArguments();
for(Type fieldArgType : fieldArgTypes){
Class fieldArgClass = (Class) fieldArgType;
System.out.println("fieldArgClass = " + fieldArgClass);
}
}

这段代码将输出fieldArgClass = java.lang.String。Type[]数组fieldArgTypes包含一个元素-一个代表实现了Type接口的java.lang.String类的对象。类实现类型接口。

原文

This article was last updated on days ago, and the information described in the article may have changed.