-- Start
反射是一个很强大的工具, 它赋予我们动态分析类和对象的能力, 下面的例子对比了采用正常方式和反射方式操作对象.
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
// ---------- 使用正常方式操作对象---------- //
// 使用构造器创建一个对象
People p = new People();
// 调用对象有参数方法
p.setName("Shang Bo");
// 调用对象的无参数的方法
String name = p.getName();
System.out.println(name);
// ---------- 使用反射方式操作对象 ---------- //
// 首先必須得到 People 的 Class 对象
Class<People> pc = People.class;
// 使用构造器创建一个对象
Constructor<People> constructor = pc.getDeclaredConstructor(); // 得到 People 的 无参构造器
People pf = constructor.newInstance(); // 调用构造器创建对象
// 调用对象有参数方法
Method setName = pc.getDeclaredMethod("setName", String.class); // 得到 People 的 setName 方法
setName.invoke(pf, "Shang Bo"); // 调用方法
// 调用对象的无参数的方法
Method getName = pc.getDeclaredMethod("getName"); // 得到 People 的 getName 方法
Object namef = getName.invoke(pf); // 调用方法
System.out.println(namef);
// 访问对象的私有域
Field f = pc.getDeclaredField("name");
f.setAccessible(true); // 必须设置成 true 才可以访问私有域
System.out.println(f.get(pf));
}
}
class People {
private String name;
public People() {
}
public People(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
显然, 为了使用反射, 我们必須先得到某一个类的 Class 实例, 虚拟机为任何类(包括原始数据类型, 数组, 枚举)都维护一个 Class 实例, 所以我们不能通过构造器来得到Class 实例, 我们有以下三种方式得到 Class 实例.
public static void main(String[] args) throws Exception {
Integer i = 0;
// 得到 Class 实例的方式
Class c = i.getClass(); // 方式 1
c = Class.forName("java.lang.Integer"); // 方式 2
c = Integer.class; // 方式 3
c = int.class; // 原始数据类型也有自己的 Class 实例
c = Integer[].class; // 数组也有自己的 Class 实例
}
一旦得到某一个类的 Class 实例, 我们就可以利用下面的方法得到类的构造器,域和方法.
getField(String name)
getFields() -- 返回所有公有域, 包括超类的公有域
getDeclaredField(String name)
getDeclaredFields() -- 返回所有域, 包括私有域, 但不包括超类中声明的域
getConstructor(Class ... parameterTypes)
getConstructors() -- 返回所有公有构造器, 包括超类的公有构造器
getDeclaredConstructor(Class ... parameterTypes)
getDeclaredConstructors() -- 返回所有构造器, 包括私有构造器, 但不包括超类中声明的构造器
getMethod(String name, Class ... parameterTypes)
getMethods() -- 返回所有公有方法, 包括超类的公有方法
getDeclaredMethod(String name, Class ... parameterTypes)
getDeclaredMethods() -- 返回所有方法, 包括私有方法, 但不包括超类中声明的方法
一旦得到了某一个类的构造器(Constructor类), 我们就可以通过下面的方法得到构造器的各个组成部分, 如: 注解, 修饰符, 参数类型, 异常类型等等. 我们还可以通过 newInstance 方法创建一个新对象. 下面是一个简单的例子.
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) throws Exception {
for (Constructor<People> c : People.class.getDeclaredConstructors()) {
// 打印构造器的注解
Annotation[] annotations = c.getDeclaredAnnotations();
for (int j = 0; j < annotations.length; j++) {
System.out.print(annotations[j]);
}
// 打印构造器的修饰符
System.out.print(Modifier.toString(c.getModifiers()));
// 打印构造器的名称
System.out.print(" " + c.getName() + "(");
// 打印构造器的参数
Class<?>[] paramTypes = c.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
if (j > 0)
System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.print(")");
// 打印构造器的异常
Class<?>[] exceptionTypes = c.getExceptionTypes();
if (exceptionTypes.length > 0)
System.out.print(" throws ");
for (int j = 0; j < exceptionTypes.length; j++) {
if (j > 0)
System.out.print(", ");
System.out.print(exceptionTypes[j].getName());
}
System.out.println("");
}
}
}
class People {
private String name;
public People() {
}
@Deprecated
public People(String name) throws Exception {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
一旦得到了某一个类的域(Field类), 我们就可以通过下面的方法得到域的各个组成部分, 如: 注解, 类型, 修饰符等. 我们还可以通过 get 和 set 方法读取和设置域的信息. 下面是一个简单的例子.
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) throws Exception {
for (Field f : People.class.getDeclaredFields()) {
// 打印域的注解
Annotation[] annotations = f.getDeclaredAnnotations();
for (int j = 0; j < annotations.length; j++) {
System.out.print(annotations[j]);
}
// 打印域的修饰符
System.out.print(" " + Modifier.toString(f.getModifiers()));
// 打印域的类型
System.out.print(" " + f.getType().getName());
// 打印域的名称
System.out.print(" " + f.getName());
}
}
}
class People {
@Deprecated
private String name;
public People() {
}
@Deprecated
public People(String name) throws Exception {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
一旦得到了某一个类的方法(Method类), 我们就可以通过下面的方法得到方法的各个组成部分, 如: 注解, 修饰符, 返回类型, 参数类型, 异常类型等. 我们还可以通过 invoke 方法来调用方法. 下面是一个简单的例子.
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) throws Exception {
for (Method m : People.class.getDeclaredMethods()) {
// 打印方法的注解
Annotation[] annotations = m.getDeclaredAnnotations();
for (int j = 0; j < annotations.length; j++) {
System.out.print(annotations[j]);
}
// 打印方法的修饰符
System.out.print(" " + Modifier.toString(m.getModifiers()));
// 打印方法的返回类型
System.out.print(" " + m.getReturnType().getName());
// 打印方法的名称
System.out.print(" " + m.getName() + "(");
// 打印方法的参数类型
Class<?>[] paramTypes = m.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
if (j > 0)
System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.print(")");
// 打印方法的异常类型
Class<?>[] exceptionTypes = m.getExceptionTypes();
if (exceptionTypes.length > 0)
System.out.print(" throws ");
for (int j = 0; j < exceptionTypes.length; j++) {
if (j > 0)
System.out.print(", ");
System.out.print(exceptionTypes[j].getName());
}
System.out.println("");
}
}
}
class People {
@Deprecated
private String name;
public People() {
}
@Deprecated
public People(String name) throws Exception {
this.name = name;
}
public String getName() {
return name;
}
@Deprecated
public void setName(String name) throws Exception {
this.name = name;
}
}
JDK 1.5 引入泛型后,Java 反射包也进行了相应的修改,添加了如下的接口,从而使反射能够分析泛型类和泛型方法。
TypeVariable 接口用来描述类型变量,如下面声明中的粗体部分。
class Test<T> {}
public static <T extends Comparable<? super T>> T min(T[] a) {}
ParameterizedType 接口用来描述泛型类或接口类型,如下面声明中的粗体部分。
public static <T extends Comparable<? super T>> T min(T[] a) {}
WildcardType 接口用来描述通配符。
GenericArrayType 接口用来描述泛型数组。
下面我们通过一个简单的例子来看看反射是如何动态分析一个泛型方法的。
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
public class Test {
public static void main(String[] args) throws Exception {
// 得到 Test 类的 Class 对象
Class<Test> test = Test.class;
// 得到 Test 类的 min 方法
Method min = test.getDeclaredMethod("min", Comparable[].class);
// 打印 min 方法的修饰符
System.out.print(Modifier.toString(min.getModifiers()));
// 打印方法的类型变量
System.out.print(" <");
TypeVariable<Method> tv = min.getTypeParameters()[0];
System.out.print(tv.getName());
System.out.print(" extends ");
ParameterizedType pt = (ParameterizedType) tv.getBounds()[0];
System.out.print(((Class) pt.getRawType()).getName());
WildcardType wt = (WildcardType) pt.getActualTypeArguments()[0];
System.out.print("<? super ");
System.out.print(((TypeVariable) (wt.getLowerBounds()[0])).getName());
System.out.print("> ");
// 打印返回类型
TypeVariable rt = (TypeVariable) min.getGenericReturnType();
System.out.print(rt.getName());
// 打印方法名
System.out.print(" ");
System.out.print(min.getName());
// 打印方法的参数
System.out.print("(");
GenericArrayType gat = (GenericArrayType) min.getGenericParameterTypes()[0];
TypeVariable gtv = (TypeVariable) gat.getGenericComponentType();
System.out.print(gtv.getName());
System.out.print("[]");
System.out.println(")");
}
// 用来测试的泛型方法
public static <T extends Comparable<? super T>> T min(T[] a) {
return null;
}
}
-- 声 明:转载请注明出处
-- Last Updated on 2012-06-16
-- Written by ShangBo on 2012-05-24
-- End