Java反射学习笔记

来源:互联网 发布:java中冒泡排序法代码 编辑:程序博客网 时间:2024/05/18 01:26

一 定义及功能

       Java的反射机制指的是,Java程序在运行过程中,对于任意一个类,都能够动态的获得这个类的任意的属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取对象属性和方法的功能称为Java语言的反射机制。

        Java反射机制可以提供一下功能:
1 在运行时判断任意一个对象所属的类;
2 在运行时调用任意一个对象的方法;
3 在运行时判断任意一个类所具有的的成员变量和方法;
4 在运行时构造任意一个类的对象;
5 生成动态代理;
      我们首先使用一个例子来说明Java反射机制是如何工作的。 

<span style="font-size:18px;">package reflect.test;</span>
<span style="font-size:18px;">import java.lang.reflect.Method;//测试类class Demo {}public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException {<span style="white-space:pre"></span>Demo demo = new Demo();System.out.println(demo.getClass().getName());}}</span>

输出结果:

reflect.test.Demo


      这样就可以获得demo对象所属的类的命名空间和类名。这个过程使用了对象的getClass()方法来载入指定的类,然后调用getName()方法来获取名称。


二 获取步骤及方式

使用Java的反射机制,需要遵循三个步骤:
1 获得你要操作的类的Class对象;
2 通过第一步获得的class对象,获取要操作的类的方法名或者属性对象;

3 操作第二步获取的属性或者对象。

Java运行的时候,无论某个类实例化多少个对象,他们都会对应一个Class对象,它表示正在运行的程序的类和接口。如何获取这个类呢?常用的方法有三个:

1 通过Class的静态方法forName(),直接输入类的全路径;
2 通过对象的getClass()方法,获得所指向的Class对象。
3 通过类名的.class语法,获得Class对象;

下面通过实例来说明,如何通过以上三个方法获取Class对象。

<span style="font-size:18px;">package reflect.test;import java.lang.reflect.Method;//测试类class Demo {}public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException {// 三种方式获取操作类的class对象Class<?> demo1 = null;Class<?> demo2 = null;Class<?> demo3 = null;// 方法一 通过输入String类的全路径try {demo1 = Class.forName("java.lang.String");} catch (Exception e) {e.printStackTrace();}// 方法二 通过实例化后的对象得到Class类String strTest = "";demo2 = strTest.getClass();// 方法三 通过类的class语法,获取Class类demo3 = String.class;// 输出Class类System.out.println(demo1.getName());System.out.println(demo2.getName());System.out.println(demo3.getName());}}</span>

输出结果:
java.lang.String
java.lang.String

java.lang.String


三 功能详解
前边我们说过了反射的五个主要用途,我们已经试验了第一个用途,通过反射获得对象所属的类,下面我们分别来说明其他的几个用途。
1 通过反射来执行对象的某个方法,代码如下:
<span style="font-size:18px;">package reflect.test;import java.lang.reflect.Method;//测试类class Display {// 带有参数的输出方法public void show(String name, String content) {System.out.println(name + content);}}public class ReflectMethod {public static void main(String[] args) {// 1 获取display类的对象Display display = new Display();Class<?> displayTest = display.getClass();// 2 获取操作方法对象Method method = null;try {method = displayTest.getMethod("show", String.class, String.class);} catch (Exception e) {e.printStackTrace();}//3 执行获得的方法try {method.invoke(display, "小盖", "你好!");} catch (Exception e) {e.printStackTrace();}}}</span>

输出结果:
小盖  你好!

前边说过,使用反射的第一步就是获取这个类,对应我们代码注释的第一步;第二步是获取你将要操作的方法对象,对应我们代码第二步,这个方法包括三个参数,第一个参数是我们要操作的那个方法名,第二个和第三个参数分别是我们要调用的那个方法的参数类型,这个方法的参数个数是根据要调用的方法的参数个数来确定的,所以,参数个数是个不确定的数据。第三步是执行这个方法,即我们的invoke方法,其实调用的就是show方法,这个方法有三个参数,第一个参数是一个对象,使我们要调用的那个类的一个对象,后边的参数是我们要调用的方法需要的参数,这个参数必须与要调用方法的参数一致。
2 通过反射来给某个类的属性赋值,代码如下:

<span style="font-size:18px;">package reflect.test;import java.lang.reflect.Field;//测试实体类class Person{private String name;private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}}public class ReflectAttribute {public static void main(String[] args){//实例化一个源对象并且赋值Person fromPerson = new Person();fromPerson.setName("小盖");fromPerson.setAge(22);//实例化一个目标对象Person toPerson = new Person();try {//给目标对象属性赋值replace(fromPerson, toPerson);} catch (SecurityException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}System.out.println(toPerson.getName() +" : "+ toPerson.getAge().toString());}public static void replace (Object fromClass,Object toClass) throws SecurityException, NoSuchFieldException{//获取源对象的类Class<?> fromObject = fromClass.getClass();//获取源对象的属性集Field[] fromFields = fromObject.getDeclaredFields();//获取目标对象的类Class<?> toObject = toClass.getClass();//定义目标对象的属性集Field toField = null;//循环源对象属性集for (Field fromField : fromFields) {//获取源对象的属性名称和对应目标对象的属性名称String name = fromField.getName();toField = toObject.getDeclaredField(name);//设置属性操作权限fromField.setAccessible(true);toField.setAccessible(true);try {//给目标对象属性赋值toField.set(toClass, fromField.get(fromClass));} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}}</span>

运行结果:
小盖 : 22

反射机制中的类有Class对应,方法有Method对应,属性由Field对应。Field提供了get和set属性,但是由于属性时私有类型,所以需要设置访问权限。本例中是通过循环分别为每个属性设置访问权限,您也可以通过设置属性集的权限来同意修改访问权限,在此不再赘述。
3 通过反射在运行时动态创建类的一个对象,代码如下:
<span style="font-size:18px;">package reflect.test;import java.lang.reflect.Field;class Student{private String stuName;private String stuNo;public String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName = stuName;}public String getStuNo() {return stuNo;}public void setStuNo(String stuNo) {this.stuNo = stuNo;}}public class ReflectClass {public static void main (String[] args){//实例化源对象Student fromStudent = new Student();fromStudent.setStuName("小盖");fromStudent.setStuNo("11050241003");//调用replace方法生成目标对象Student toStudent = (Student)replace(fromStudent);System.out.println("姓名: " + toStudent.getStuName());System.out.println("学号: " + toStudent.getStuNo());}private static Object replace(Object fromClass){//1--2 获得源对象的类和属性集、定义目标对象Class<?> fromObject = fromClass.getClass();Field[] fromFields = fromObject.getDeclaredFields();Object toObject = null;try {//3 通过类直接创建目标对象toObject = fromObject.newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}//给目标对象创建属性等for (Field fromField : fromFields) {fromField.setAccessible(true);try {fromField.set(toObject, fromField.get(fromClass));} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}return toObject;}}</span>

输出结果:
姓名: 小盖
学号: 11050241003

Class的newInstance方法只能创建无参数的构造函数的类,如果构造函数带有参数,那么就需要另外一种方式。属性赋值和上例一样,这里不再赘述。

四 注意事项

        在获取类的方法、属性和构造函数时,会有getxxx和getDeclatedxxx两种方法。它们的区别是前者只能返回访问权限为public的方法和属性,包括父类的;后者返回的是所有访问权限的方法和属性,不包括父类的。

五 总结

        反射的应用范围很广,使用反射可以降低程序之间的耦合性,增加程序的灵活性。

         以后会根据实际应用情况更加深入的研究反射,敬请期待。

1 0
原创粉丝点击