今天,自己特意复习了一下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);