反射

来源:互联网 发布:mac os 10.7的升级包 编辑:程序博客网 时间:2024/06/06 02:00

-- 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(); // 方式 1c = Class.forName("java.lang.Integer"); // 方式 2c = Integer.class; // 方式 3c = 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() {}@Deprecatedpublic 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 {@Deprecatedprivate String name;public People() {}@Deprecatedpublic 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 {@Deprecatedprivate String name;public People() {}@Deprecatedpublic People(String name) throws Exception {this.name = name;}public String getName() {return name;}@Deprecatedpublic 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;}}


---更多参见:Java 精萃
-- 声 明:转载请注明出处
-- Last Updated on 2012-06-16
-- Written by ShangBo on 2012-05-24
-- End
原创粉丝点击