今天,自己特意复习了一下java的反射机制,对一个类中的属性、方法及构造方法通过反射机制进行操作,关于反射机制的一些概念就不多说了,大家可以看我以前的java基础博客进行了解,下面的都是一些代码:
定义要操作的类(Person)及它的一个父类(Parent),然后在其里面定义了一些方法和属性:
Person类:
package com.xin.test; public class Person extends Parent{ private int personId; public String personName; public Person(){ } public Person(String personName){ this.parentName=personName; } private Person(int personId){ this.personId=personId; } private int mul(int a,int b){ return a*b; } protected int del(int a,int b){ return a/b; } public int add(int a,int b){ return a+b; } }
Parent类:
package com.xin.test; public class Parent { private int parentId; public String parentName; public Parent(){ } public Parent(String parentName){ this.parentName=parentName; } public void sayHello(){ System.out.println("hello world"); } }
下面我们定义一个反射操作类ReflectTest来操作Person中的一些属性和方法:
1、获得Person字节码的三种方式,根据自己应用的场景选择相应的方式:
//获得字节码的几种方式,得到信息:class com.xin.test.Person public Class<?> getClazz()throws Exception{ //第一种方式 Class<?> clazz=Class.forName("com.xin.test.Person"); //第二种方式 clazz=Person.class; //第三种方式 Person p=new Person(); clazz=p.getClass(); return clazz; }
2、利用反射机制实例化对象:
//利用反射机制实例化对象 public void getObject()throws Exception{ Class<?> clazz=Class.forName("com.xin.test.Person"); System.out.println("-------使用下面方法实例化对象,必须提供无参数构造方法--------------"); Person person=(Person)clazz.newInstance(); person.sayHello(); System.out.println("---------实例化有参数构造方法,先获得所有构造方法,再进行实例化-----------"); Constructor<?>[] cons=clazz.getConstructors(); person=(Person)cons[0].newInstance(); person.sayHello(); }
3、利用反射机制操作属性:
//利用反射机制操作属性 public void operateField()throws Exception{ Class<?> clazz=Class.forName("com.xin.test.Person");//获得字节码信息 //访问特定的属性,只能获取public访问修饰的属性信息:public int com.xin.test.Person.age System.out.println("-------得到类中特定的属性,该属性只能是public的---------"); Field field=clazz.getField("personName"); System.out.println(field); System.out.println("-------得到自身和父类的所有属性,属性只能是public的---------"); //访问自身和父类的所有属性 Field[] fields=clazz.getFields(); for(Field field2:fields){ System.out.println(field2); } System.out.println("-------得到自身类中一切访问修饰符的特定属性--------"); //可以获取一切访问修饰的属性信息,包括private修饰符修饰的属性 field=clazz.getDeclaredField("personId"); System.out.println(field); //要操作private属性,需要给其添加下面的权限 field.setAccessible(true); Person p=(Person)clazz.newInstance();//创建Person的一个实例对象,调用无参数构造函数 System.out.println("----------给属性赋值和取值------------"); field.setInt(p, 23);//给属性赋值 System.out.println(field.getInt(p));//取得相应属性的值 System.out.println(field.getClass());//获得属性字节码文件 System.out.println("------得到自身类中一切访问修饰符的所有属性---------"); fields=clazz.getDeclaredFields(); for(Field field2:fields){ System.out.println(field2); } System.out.println("----------取得属性访问修饰符------------------"); System.out.println(Modifier.toString(field.getModifiers())); }
4、利用反射机制操作构造方法:
//利用反射机制操作构造方法 public void operateConstructor()throws Exception{ Class<?> clazz=Class.forName("com.xin.test.Person");//获得字节码信息 System.out.println("------调用自身无参public构造方法----------"); Constructor<?> con=clazz.getConstructor(); System.out.println(con); System.out.println("------调用自身有参public构造方法----------"); con=clazz.getConstructor(String.class); System.out.println(con); System.out.println("----------调用自身任何访问修饰符构造方法--------------"); con=clazz.getDeclaredConstructor(int.class); System.out.println(con); System.out.println("----------调用自身所有的public构造方法--------------"); Constructor[] cons=clazz.getConstructors(); for(Constructor con2:cons){ System.out.println(con2); } System.out.println("----------调用自身所有的任意修饰符修饰的构造方法--------------"); cons=clazz.getDeclaredConstructors(); for(Constructor con2:cons){ System.out.println(con2); } System.out.println("---------利用构造方法实例化对象-------------"); cons=clazz.getConstructors(); Person p1=(Person)cons[0].newInstance(); System.out.println("实例化无参数构造方法:"+p1); p1=(Person)cons[1].newInstance("Mary"); System.out.println("实例化有参数构造方法:"+p1); }
5、利用反射机制操作方法:
//利用反射机制操作方法 public void operateMethod()throws Exception{ Class<?> clazz=Class.forName("com.xin.test.Person");//获得字节码信息 System.out.println("--------获得自身类中所有的方法-----------"); //获得自身类中所有的方法,private方法也可获取到,打印输出private int com.xin.test.Person.mul(int,int) Method[] methods=clazz.getDeclaredMethods(); for(Method method:methods){ System.out.println(method); } System.out.println("--------获得自身类以及父类的所有的public方法,包括Object类-----------"); //获得自身类public以及父类的public方法,还包括Object类 Method[] methods2=clazz.getMethods(); for(Method method:methods2){ System.out.println(method); } System.out.println("---------获得自身类public修饰的特定方法-----------"); Method method=clazz.getMethod("add", int.class,int.class);//获得add方法,add方法的访问修饰符需为public System.out.println(method.getModifiers()+"---"+method.getName()+"---"+method.getDefaultValue()); System.out.println(method.invoke(clazz.newInstance(), 3,4));//执行方法 System.out.println("---------获得自身类任意访问修饰符修饰的特定方法--------"); Method method2=clazz.getDeclaredMethod("mul", int.class,int.class);//获得mul方法,mul方法访问修饰符可以为任意修饰符,包括private System.out.println(method2.getModifiers()+"---"+method2.getName()+"---"+method2.getDefaultValue()); System.out.println("访问修饰符为"+Modifier.toString(method2.getModifiers())); method2.setAccessible(true);//如果方法的访问修饰符为private,需要加上这个,否则调用invoke方法会报错 System.out.println(method2.invoke(clazz.newInstance(), 3,4));//执行方法 System.out.println("---------获得方法参数类型---------"); //获得方法mul中的参数类型 Type[] types=method2.getGenericParameterTypes(); for(Type type:types){ System.out.println("方法中的参数类型为:"+type); } System.out.println("---------获得方法返回值类型-----------"); //获得方法mul中的返回值类型 System.out.println("方法返回值类型为:"+method2.getGenericReturnType()); }
6、利用反射机制操作父类信息:
//使用反射操作父类信息 public void operateParent()throws Exception{ Class<?> clazz=Class.forName("com.xin.test.Person");//获得字节码信息 System.out.println("-----获得父类字节码-------------"); clazz=clazz.getSuperclass(); System.out.println(clazz); System.out.println("-----获得父类构造函数信息-------------"); Constructor<?>[] cons=clazz.getConstructors(); for(Constructor<?> con:cons){ System.out.println(con); } }
其实利用反射机制还可以获取很多信息,例如接口类、注解信息等,没有一一列出,大家可以自己去尝试一下,我在测试这些类的时候,其实有一个疑问,就是clazz.getFields()、clazz.getMethods()可以获取父类中定义的public属性和方法,为什么clazz.getConstructors()却获取不到父类的构造方法呢,可能跟java机制有关吧,因为先要有父亲才会有儿子,这也是个人猜测;
在操作私有的属性和方法的时候,记得要给它们添加访问权限:setAccessible(true);