java.lang.reflect是“反射”包,其中定义了各个元数据的类。其继承关系如下图所示:
一、最底层的接口
几个蓝色色框中,定义了最底层的几个接口:
AnnotatedElement接口,这个接口中的方法,用来获取元素上的注解(如果是在框架中,通常是被定义为“运行时可见”的注解)。可以被注解的元素均继承了这个接口,如Method、Field、Class等。
此类型可以用来:获得一个元素的所有注解、特定类型的注解,查看元素上是否存在这种注解。
Type接口,代表一个类型。类型并非只有Class类,下面会讲到,还有别的类型(主要是和泛型的类型参数相关,类型参数的“擦除”并不是了无痕迹,在某些特定的情况下,仍然可以获取到泛型的类型参数信息)。
此接口只有一个getTypeName方法,用来获取类型的名字。其他的功能都定义在子类中。
Member接口,代表一个“成员”,从上面的图中可见,方法、构造器、字段三种元素继承了这一个接口。其中定义了两个常量:
-
PUBLIC,表示一个类型所有的“公有”成员,而不论这个成员是在这个类、还是这个类的基类中定义的。
-
DECLARED,表示这个类型中定义的成员,而不是从别的地方“继承”过来的,不论是public、protected或者private都行。
这个接口中定义了一些方法,例如:获取成员的名字,获取成员的限定符(public、statis、final这一类,但是是一个int值。需要自己按位解析),是哪个类中直接定义的,是否是编译器产生的(一些方法可能是编译器自动产生的,而不是在代码中定义的,例如内部类相关的一些方法)
二、Type接口衍生的类型
泛型有“擦除”的机制,这是很多人都知道的。但是,作为“局部变量”和“字段”的泛型实例对象,仍然有所不同,字段保留了更多的泛型信息。因此,下面的代码示例,都使用了类字段,而非局部变量。
1、ParameterizedType
ParameterizedType接口,表示一个被参数化的类型。几个重要的方法有:
- getRawType,得到参数化类型的原始类型,例如下面程序运行的结果,返回了Map.class
- getActualTypeArguments,得到类型参数的列表
示例代码如下:
public class Parameterized {
public static void main(String[] argv) throws Exception {
Class<MySelf> cls = MySelf.class;
Field field = cls.getField("strs");
ParameterizedType type = (ParameterizedType)field.getGenericType();
System.out.println("getRawType:" + type.getRawType().getTypeName());
Type[] types = type.getActualTypeArguments();
for (Type t : types) {
System.out.println("getActualTypeArguments:" + t.getTypeName());
}
}
}
class MySelf {
public Map<String, Integer> strs;
}
运行结果如下:
getRawType:java.util.Map
getActualTypeArguments:java.lang.String
getActualTypeArguments:java.lang.Integer
2、WildcardType
WildcardType表示一个类型通配符,例如?, ? extends Number, ? super XXX这样的类型参数。
有两个重要方法:
- getUpperBounds,返回? extends xxx中的类型
- getLowerBounds,返回? super xxx中的类型
示例代码如下:
public class Wildcard {
public static void main(String[] argv) throws Exception {
Class<WildcardInner> cls = WildcardInner.class;
Field fa = cls.getField("a");
Field fb = cls.getField("c");
WildcardType wta = (WildcardType)((ParameterizedType)fa.getGenericType()).getActualTypeArguments()[0];
System.out.println("wta:" + wta.getTypeName());
System.out.println("upper:" + wta.getUpperBounds()[0]);
WildcardType wtb = (WildcardType)((ParameterizedType)fb.getGenericType()).getActualTypeArguments()[0];
System.out.println("wtb:" + wtb.getTypeName());
System.out.println("lower:" + wtb.getLowerBounds()[0]);
}
}
class WildcardInner {
public List<? extends A> a;
public Set<? super C> c;
}
class A {}
interface B {}
class C extends A implements B {}
运行结果如下:
wta:? extends A
upper:class .A
wtb:? super C
lower:class C
3、GenericArrayType
GenericArrayType表示一个数组类型,其组成元素是ParameterizedType,或者是TypeVariable。
其只有一个方法:getGenericComponentType,得到元素的参数类型。
示例代码如下:
public class GenericArray {
public static void main(String[] argv) throws Exception {
Class<GenericArrayInner> cls = GenericArrayInner.class;
Field f = cls.getField("lists");
GenericArrayType type = (GenericArrayType)f.getGenericType();
ParameterizedType pType = (ParameterizedType) type.getGenericComponentType();
System.out.println(pType.getTypeName());
}
}
class GenericArrayInner {
public List<Integer>[] lists;
}
运行结果:
java.util.List<java.lang.Integer>
三、Parameter
Parameter代表方法、构造器的参数。
需要在编译的时候,加上-parameters参数,才能通过getName方法,拿到参数的名称。
Parameter类上,有用的方法有:
- getName,得到参数的名称。但是注意要在编译的时候,加上-parameters参数。如果不加,得到的就是arg0,arg1这样的
- getDeclaringExecutable,得到参数属于的方法或构造器
- getType,得到参数的类型
- getParameterizedType,得到参数化的类型
- isVarArgs,是否是参数列表(String ... strs这样的参数,调用的时候参数数量不定,但是只能放在最后)
- getModifier,得到修饰符int值(但是参数的修饰符,也只想到一个final,除此以外不知道能有什么了)
示例代码如下:
public class ParameterTest {
public static void main(String[] argv) throws Exception {
Class<ParameterInner> cls = ParameterInner.class;
Method method = cls.getDeclaredMethod("fun", int.class, List.class, String[].class);
Parameter[] parameters = method.getParameters();
for (Parameter p : parameters) {
System.out.println("getName: " + p.getName());
System.out.println("getDeclaringExecutable: " + p.getDeclaringExecutable());
System.out.println("getParameterizedType: " + p.getParameterizedType());
System.out.println("isVarArgs: " + p.isVarArgs());
System.out.println("getModifiers: " + p.getModifiers());
System.out.println("----");
}
}
}
class ParameterInner {
private void fun(final int number, List<Double> detail, String ... strs) {
//do nothing
}
}
运行结果:
getName: number
getDeclaringExecutable: private void my.reflect.ParameterInner.fun(int,java.util.List,java.lang.String[])
getParameterizedType: int
isVarArgs: false
getModifiers: 16
----
getName: detail
getDeclaringExecutable: private void my.reflect.ParameterInner.fun(int,java.util.List,java.lang.String[])
getParameterizedType: java.util.List<java.lang.Double>
isVarArgs: false
getModifiers: 0
----
getName: strs
getDeclaringExecutable: private void my.reflect.ParameterInner.fun(int,java.util.List,java.lang.String[])
getParameterizedType: class [Ljava.lang.String;
isVarArgs: true
getModifiers: 0
----
四、GenericDeclaration与TypeVariable
GenericDeclaration是所有带有类型参数的实体的基类,声明很简单。只有一个方法,用来获取尖括号中的占位符信息:
public interface GenericDeclaration extends AnnotatedElement {
//得到其中所有占位符
public TypeVariable<?>[] getTypeParameters();
}
TypeVariable就是泛型类中的参数列表,也就是类型后面尖括号中的内容。声明如下:
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
//得到占位符边界,例如E extends xxx中的xxx
Type[] getBounds();
//得到占位符所属于的泛型类型
D getGenericDeclaration();
//得到占位符的名称,通常是K,V这样的
String getName();
//抱歉,没有搞清楚
AnnotatedType[] getAnnotatedBounds();
}
示例代码:
public class GenericDeclarationTest {
public static void main(String[] argv) {
GenericDeclaration clz = Generic.class;
TypeVariable[] typeVariables = clz.getTypeParameters();
int i = 1;
for (TypeVariable tv : typeVariables) {
System.out.println("variableNo: " + i++);
System.out.println("getName: " + tv.getName());
System.out.print("getBounds: ");
for (Type t : tv.getBounds()) {
System.out.print(t + ",");
}
System.out.println("");
System.out.println("getGenericDeclaration: " + tv.getGenericDeclaration());
System.out.print("getAnnotatedBounds: ");
for (AnnotatedType at : tv.getAnnotatedBounds()) {
System.out.print(at + ",");
}
System.out.println("");
System.out.println("");
}
}
}
class Generic<K extends Integer, V extends List> {
}
执行结果:
variableNo: 1
getName: K
getBounds: class java.lang.Integer,
getGenericDeclaration: class my.reflect.Generic
getAnnotatedBounds: sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@1540e19d,
variableNo: 2
getName: V
getBounds: interface java.util.List,
getGenericDeclaration: class my.reflect.Generic
getAnnotatedBounds: sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@677327b6,
五、AnnotatedType及其子类
六、Field与Executable及其子类