java反射机制讲授及示例
java反射机制讲解及示例
java反射机制作用:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的方法
Reflection是java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(修饰符,诸如public,static等等),superclass(父类,例如Object),实现之interfaces(接口,例如Serializable),也包括fields(成员变量)和methods(方法)的所有信息,并可于运行时修改fields内容或调用methods。
通过反射可以去改变一个私有方法,一个私有成员变量(打破类的包装机制)
尽管java不是动态语言,但却有个非常突出的动态相关机制:反射,意思是指我们可以在运行时加载,探知,使用编译期间完全未知的classes。(即java可以加载一个运行时才知道其名称的类,获悉其完整构造(不包括methods定义,只能得到方法声明),并生成其对象实体,或对其fields设值,或唤起其methods)。这种看透class的能力称为introspection。
java的反射机制,需要使用java.lang.reflect包:
-Class类:代表一个类
-Fields类:类的成员变量(类属性)
-Method类:代表类的方法
-Constructor类:类的构造方法
-Array类:提供了动态创建数组,以及访问数组的元素的静态方法
反射时,前面四个类是一定会用到的
结果:
反射生成数组:
java反射机制作用:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的方法
Reflection是java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(修饰符,诸如public,static等等),superclass(父类,例如Object),实现之interfaces(接口,例如Serializable),也包括fields(成员变量)和methods(方法)的所有信息,并可于运行时修改fields内容或调用methods。
通过反射可以去改变一个私有方法,一个私有成员变量(打破类的包装机制)
程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言:Perl,Python,Rudy是动态语言,C++,java,C#不是动态语言。(如图,javaScript是动态语言)
尽管java不是动态语言,但却有个非常突出的动态相关机制:反射,意思是指我们可以在运行时加载,探知,使用编译期间完全未知的classes。(即java可以加载一个运行时才知道其名称的类,获悉其完整构造(不包括methods定义,只能得到方法声明),并生成其对象实体,或对其fields设值,或唤起其methods)。这种看透class的能力称为introspection。
java的反射机制,需要使用java.lang.reflect包:
-Class类:代表一个类
-Fields类:类的成员变量(类属性)
-Method类:代表类的方法
-Constructor类:类的构造方法
-Array类:提供了动态创建数组,以及访问数组的元素的静态方法
反射时,前面四个类是一定会用到的
这个方法可以获得所有方法描述。类似的有getDeclaredFields();
例子DumpMethod.java:读取命令行参数指定的类名,然后打印这个类所具有的方法信息。
package com.wws.reflect; import java.lang.reflect.Method; public class DumpMethod { public static void main(String[] args) throws Exception { //获得String的类 Class<?> classType =Class.forName("java.lang.String"); //获得并返回类的所有方法 Method[] methods =classType.getDeclaredMethods(); for(Method method:methods) { System.out.println(method); } } }
结果:
改为获取传入实体的类方法信息:
package com.wws.reflect; import java.lang.reflect.Method; public class DumpMethod2 { public static void main(String[] args) throws Exception { //获得命令行输入类名的类型 Class<?> classType =Class.forName("arg[0]"); //获得并返回类的所有方法 Method[] methods =classType.getDeclaredMethods(); for(Method method:methods) { System.out.println(method); } } }传人参数:
效果:
接下来写个简单程序
用反射改造:
package com.wws.reflect; import java.lang.reflect.Method; import java.sql.ResultSet; public class InvokeTester { public int add(int parm1,int parm2) { return parm1+parm2; } public String echo(String message) { return "hello:"+message; } public static void main(String[] args)throws Exception { /*获取java类的几种方法: 通过Class类的静态方法:forName(XX); String.class,getClass()*/ Class<?> classType= InvokeTester<strong>.class</strong>; Object invokeTester =classType.<strong>newInstance()</strong>; /*System.out.println(invokeTester instanceof InvokeTester); 返回true*/ /*Method java.lang.Class.<strong>getMethod(String name, Class<?>... parameterTypes)</strong> 参数一:目标方法名 参数二:目标方法的参数类型数组*/ Method addMethod=classType.getMethod("add", new Class[]{int.class,int.class} ); /*调用invoke实现对目标方法的调用 * 参数一:实例名 * 参数二:接受什么参数 * */ Object result=addMethod<strong>.invoke(invokeTester,new java.lang.Object[]{1,2});</strong> System.out.println((Integer)result); Method echoMethod=classType.getMethod("echo", new Class[]{String.class}); Object result2=echoMethod.invoke(invokeTester, new Object[]{"wws"}); System.out.println((String)result2); } }运行结果:
通过Class类的静态方法:
forName(XX);
String.class;
getClass();
newInstance()不会生成带参数方法的实例,此时应该用Constructor的newInstance(Object ...initargs),即用类getConstructor(new Class[ ] { }).newInstance(new Object[ ]{ });
例子2:实现get,set方法:
public class CopyObject { public Object copyObject(Object object) throws Exception { // 1.获取待操作类的一个Class对象 Class<?> classType = object.getClass(); // 2.获取待操作类的一个实例 Constructor<?> constructor = classType .getConstructor(new Class<?>[] {}); Object copyObj = constructor.newInstance(new Object[] {}); // 3.获取被拷贝类的成员变量 Field[] fields = classType.getDeclaredFields(); for (Field field : fields) { // 4.遍历数组获取各个成员变量名字 String name = field.getName();// 获取成员变量名字; // 5.操作字符串获取成员变量的set和get方法名字; String firstLetter = name.substring(0, 1).toUpperCase(); String getMethodName = "get" + firstLetter + name.substring(1); String setMethodName = "set" + firstLetter + name.substring(1); Method getMethod = classType.getMethod(getMethodName, new Class<?>[] {}); Method seMethod = classType.getMethod(setMethodName, new Class<?>[] { field.getType() }); /*最开始认为以下两个invoke方法的第一和参数都应该调用copyObj, * 但是最终的结果为输出为默认的空值。 * copyObj:程序前面通过Constructor类的newInstance方法 * 获取待操作类的一个实例; //Object value = getMethod.invoke(copyObj, new Object[] {}); //seMethod.invoke(copyObj, new Object[] { value }); /*现在改用如下方式了,输出就正常了 * 所以产生疑惑:为什么第一个方法调用的object对象而不是copyObj呢? * */ Object value = getMethod.invoke(object, new Object[] {}); seMethod.invoke(copyObj, new Object[] { value }); } return copyObj; } public static void main(String[] args) throws Exception { Student student = new Student("Tom", 21); student.setId(111030805); CopyObject copy = new CopyObject(); Student student2 = (Student) copy.copyObject(student); System.out.println(student2.getId() + " " + student2.getName() + " " + student2.getAge()); } } // 一个被反射的JavaBean class Student { private long id; private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public long getId() { return id; } public void setId(long id) { this.id = id; } } 更多 0
反射生成数组:
生成多维数组:
输出结果:37,创建了一个5,10,15的三维数组。
利用反射调用类的私有方法: