Java反射的概念
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制
Java反射机制主要提供下面几种用途:
1.在运行时判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断任意一个类所具有的成员变量和方法
4.在运行时调用任意一个对象的方法
首先看一个简单的例子,通过这个例子来理解Java的反射机制是如何工作的
import java.lang.reflect.Method; /** * Java 反射练习。 * * @author Wanggc */ public class ForNameTest { /** * 入口函数。 * * @param args * 参数 * @throws Exception * 错误信息 */ public static void main(String[] args) throws Exception { // 获得Class Class<?> cls = Class.forName(args[0]); // 通过Class获得所对应对象的方法 Method[] methods = cls.getMethods(); // 输出每个方法名 for (Method method : methods) { System.out.println(method); } } }
代码示例如下
使用java的反射机制,一般需要遵循三步:
1.获得你想操作类的Class对象
2.通过第一步获得的Class对象去取得操作类的方法或是属性名
3.操作第二步取得的方法或是属性
Java运行的时候,某个类无论生成多少个对象,他们都会对应同一个Class对象,它表示正在运行程序中的类和接口。如何取得操作类的Class对象,常用的有三种方式:
1.调用Class的静态方法forName,如上例;
2.使用类的.class语法,如:Class<?> cls = String.class;
3.调用对象的getClass方法,如:String str = "abc";Class<?> cls = str .getClass();
下面将通过实例讲述如何通过前面所诉的三步来执行某对象的某个方法:
3 import java.lang.reflect.Method; 4 5 /** 6 * Java 反射练习。 7 * 8 * @author Wanggc 9 */ 10 public class ReflectionTest { 11 public static void main(String[] args) throws Exception { 12 DisPlay disPlay = new DisPlay(); 13 // 获得Class 14 Class<?> cls = disPlay.getClass(); 15 // 通过Class获得DisPlay类的show方法 16 Method method = cls.getMethod("show", String.class); 17 // 调用show方法 18 method.invoke(disPlay, "Wanggc"); 19 } 20 } 21 22 class DisPlay { 23 public void show(String name) { 24 System.out.println("Hello :" + name); 25 } 26 }
代码示例如下
上例讲述了如何通过反射调用某个类的方法,下面将再通过一个实例讲述如何通过反射给某个类的属性赋值:
3 import java.lang.reflect.Field; 4 5 /** 6 * Java 反射之属性练习。 7 * 8 * @author Wanggc 9 */ 10 public class ReflectionTest { 11 public static void main(String[] args) throws Exception { 12 // 建立学生对象 13 Student student = new Student(); 14 // 为学生对象赋值 15 student.setStuName("Wanggc"); 16 student.setStuAge(24); 17 // 建立拷贝目标对象 18 Student destStudent = new Student(); 19 // 拷贝学生对象 20 copyBean(student, destStudent); 21 // 输出拷贝结果 22 System.out.println(destStudent.getStuName() + ":" 23 + destStudent.getStuAge()); 24 } 25 26 /** 27 * 拷贝学生对象信息。 28 * 29 * @param from 30 * 拷贝源对象 31 * @param dest 32 * 拷贝目标对象 33 * @throws Exception 34 * 例外 35 */ 36 private static void copyBean(Object from, Object dest) throws Exception { 37 // 取得拷贝源对象的Class对象 38 Class<?> fromClass = from.getClass(); 39 // 取得拷贝源对象的属性列表 40 Field[] fromFields = fromClass.getDeclaredFields(); 41 // 取得拷贝目标对象的Class对象 42 Class<?> destClass = dest.getClass(); 43 Field destField = null; 44 for (Field fromField : fromFields) { 45 // 取得拷贝源对象的属性名字 46 String name = fromField.getName(); 47 // 取得拷贝目标对象的相同名称的属性 48 destField = destClass.getDeclaredField(name); 49 // 设置属性的可访问性 50 fromField.setAccessible(true); 51 destField.setAccessible(true); 52 // 将拷贝源对象的属性的值赋给拷贝目标对象相应的属性 53 destField.set(dest, fromField.get(from)); 54 } 55 } 56 } 57 58 /** 59 * 学生类。 60 */ 61 class Student { 62 /** 姓名 */ 63 private String stuName; 64 /** 年龄 */ 65 private int stuAge; 66 67 /** 68 * 获取学生姓名。 69 * 70 * @return 学生姓名 71 */ 72 public String getStuName() { 73 return stuName; 74 } 75 76 /** 77 * 设置学生姓名 78 * 79 * @param stuName 80 * 学生姓名 81 */ 82 public void setStuName(String stuName) { 83 this.stuName = stuName; 84 } 85 86 /** 87 * 获取学生年龄 88 * 89 * @return 学生年龄 90 */ 91 public int getStuAge() { 92 return stuAge; 93 } 94 95 /** 96 * 设置学生年龄 97 * 98 * @param stuAge 99 * 学生年龄 100 */ 101 public void setStuAge(int stuAge) { 102 this.stuAge = stuAge; 103 } 104 }
代码示例如下
前面讲述了如何用Java反射机制操作一个类的方法和属性,下面再通过一个实例讲述如何在运行时创建类的一个对象:
3 import java.lang.reflect.Field; 4 5 /** 6 * Java 反射之属性练习。 7 * 8 * @author Wanggc 9 */ 10 public class ReflectionTest { 11 public static void main(String[] args) throws Exception { 12 // 建立学生对象 13 Student student = new Student(); 14 // 为学生对象赋值 15 student.setStuName("Wanggc"); 16 student.setStuAge(24); 17 // 建立拷贝目标对象 18 Student destStudent = (Student) copyBean(student); 19 // 输出拷贝结果 20 System.out.println(destStudent.getStuName() + ":" 21 + destStudent.getStuAge()); 22 } 23 24 /** 25 * 拷贝学生对象信息。 26 * 27 * @param from 28 * 拷贝源对象 29 * @param dest 30 * 拷贝目标对象 31 * @throws Exception 32 * 例外 33 */ 34 private static Object copyBean(Object from) throws Exception { 35 // 取得拷贝源对象的Class对象 36 Class<?> fromClass = from.getClass(); 37 // 取得拷贝源对象的属性列表 38 Field[] fromFields = fromClass.getDeclaredFields(); 39 // 取得拷贝目标对象的Class对象 40 Object ints = fromClass.newInstance(); 41 for (Field fromField : fromFields) { 42 // 设置属性的可访问性 43 fromField.setAccessible(true); 44 // 将拷贝源对象的属性的值赋给拷贝目标对象相应的属性 45 fromField.set(ints, fromField.get(from)); 46 } 47 48 return ints; 49 } 50 } 51 52 /** 53 * 学生类。 54 */ 55 class Student { 56 /** 姓名 */ 57 private String stuName; 58 /** 年龄 */ 59 private int stuAge; 60 61 /** 62 * 获取学生姓名。 63 * 64 * @return 学生姓名 65 */ 66 public String getStuName() { 67 return stuName; 68 } 69 70 /** 71 * 设置学生姓名 72 * 73 * @param stuName 74 * 学生姓名 75 */ 76 public void setStuName(String stuName) { 77 this.stuName = stuName; 78 } 79 80 /** 81 * 获取学生年龄 82 * 83 * @return 学生年龄 84 */ 85 public int getStuAge() { 86 return stuAge; 87 } 88 89 /** 90 * 设置学生年龄 91 * 92 * @param stuAge 93 * 学生年龄 94 */ 95 public void setStuAge(int stuAge) { 96 this.stuAge = stuAge; 97 } 98 }
代码示例如下
补充:在获得类的方法、属性、构造函数时,会有getXXX和getgetDeclaredXXX两种对应的方法。之间的区别在于前者返回的是访问权限为public的方法和属性,包括父类中的;但后者返回的是所有访问权限的方法和属性,不包括父类的