Java反射机制原理
Java中万物皆对象,类class也是对象,是一个名为Class的类的对象。
所以就可以通过这个Class类类型的对象class,用对象访问类的属性和方法。
Class是对类的抽象(每个类对应一份字节码)。一般情况下,比如A a = new A();
直接通过a对象调用方法即可。但是在有些场景下,这样是做不到的,
比如类名A是通过参数传递过来的,这时候你就无法通过new的方法创建对象,需要先加载这个类,
获取Method对象,然后用Method已反射的形式调用相应的方法。
如何获得Class的类类型
先声明一个类text的对象t;
text1 t = new text1();
有三种方式可以来获得类类型:
Class t0 = text.class;//通过类获得类类型,说明Class类中隐含着一个class的对象
Class t1 = t.getClass();//通过对象获得类类型
Class t2 = null;
text t4 = null;
try {
t2 = Class.forName("classReflex.text");// 通过类的全名获得类类型
t4 = (text) t0.newInstance();// 通过类类型获得类的对象
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
进入正题:通过类类型来实现对类的成员变量、方法、构造方法的访问和调用。
首先是一个类text1
public class text1 {
public int x;
protected boolean b;
private String s;
public text1() {
// TODO Auto-generated constructor stub
}
public void f0() {
System.out.println("我爱计算机!我爱Android!");
}
private void f0_private() {
System.out.println("就算我是私有的方法!我爱计算机!我爱Android!");
}
public void f1(int i, String s1, boolean b) {
}
public int f2(int i, int s1, int b) {
return i;
}
public String f3(String i, String s1, String b) {
return i;
}
}
利用对象获得类的成员变量
- 利用对象获得类类型Class c = object.getClass();
- 通过getName()方法获得类的名称。
- getDeclaredFields()会返回类自己定义的所有的成员属性的Field集合,(领域)
- 通过Class type = field.getType();获得属性的类类型,getName()就能得到属性的具体类型了
- 关于属性的调用类似于下文的方法的调用
public static void printClassAttribute(Object object) {
// 首先获得类的信息,先获得类的类型。
Class c = object.getClass();
// 获得类的名字,传入的是什么类型,就表示什么类型,而不是父类object类型。
System.out.println("类的名称:" + c.getName());
System.out.println("类的成员属性:");
Field[] Fields = c.getDeclaredFields();
if (Fields.length > 0) {
for (Field field : Fields) {
Class type = field.getType();
System.out.println("field.getName()-->" + field.getName());
System.out
.println(field.getModifiers() + " " + type.getSimpleName() +
" m" + type.getSimpleName() + ";");
}
} else {
System.out.println("没有成员属性");
}
}
利用对象获得类的成员方法
通过类类型对象访问类所有的方法
- c.getDeclaredMethods();通过类类型的对象获得方法类的对象集合Method的集合。
- 通过Method对象的getReturnType()获得方法的返回类型的类类型对象
- 同股票method.getParameterTypes()获得方法的输入形参的类类型集合。之后就好办啦,通过类类型得到类型。
通过类类型对象调用类的方法
- Methodm m= c.getMethod(“方法名”, 形参的类类型集合);获得指定方法的对象
- 如果该方法是私有方法需要现声明该方法访问无障碍setAccessible(true);
- 之后调用m.invoke(c.newInstance,”实参”集合);调用类的方法。
- 当然如果是静态方法就不需要传入类型对象,只需要传入类类型对象c就可以了
public static void printClassMethod(Object object) {
// 首先获得类的信息,先获得类的类型。
Class c = object.getClass();
// 获得类的名字,传入的是什么类型,就表示什么类型,而不是父类object类型。
System.out.println("类的名称:" + c.getName());
System.out.println("类的成员方法:");
/*
* Method类型是方法的类型。即:方法也是对象,是类型Method的对象
* getMethods()获得类的所有成员方法,包括从父类继承来的方法
* getDeclaredMethods()获得类自己定义的成员方法。不包含父类的方法
*/
// Method[] methods = c.getMethods();
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
// 获得方法的返回值的类类型
Class returnTyoe = method.getReturnType();
System.out.print(returnTyoe.getSimpleName() + " " + method.getName() + "(");
// 获得方法所有的形参数组
Class[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
Class parameterType = parameterTypes[i];
if (i != 0)
System.out.print(" , ");
System.out.print(parameterType.getSimpleName() + " par" + i);
}
System.out.println(");");
}
System.out.println("methods.length-->" + methods.length);
/**
* 利用反射调用public方法f0();<br/>
* 先获得方法的对象Method类型的,由方法对象调用对象的方法
*/
Method m;
try {
m = c.getMethod("f0", null);
m.invoke(c.newInstance(), null);// 通过类的对象调用对象的方法,后面的是参数
// 如果的调用静态方法,就不必传入类的对象了,而只需要传递类类型就可以了m.invoke(c, null);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException |
IllegalArgumentException
| InvocationTargetException | InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
* 利用反射调用private方法f0(); <br/>
* m_private.setAccessible(true);//访问私有方法的关键步骤,设置为访问无障碍
*/
Method m_private;
try {
m_private = c.getDeclaredMethod("f0_private", null);
m_private.setAccessible(true);// 访问私有方法的关键步骤,设置为访问无障碍,但是也只能访问该类类型能访问到的方法,子类就无法访问父类的私用方法
m_private.invoke(c.newInstance(), null);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException |
IllegalArgumentException| InvocationTargetException | InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
利用对象获得类的构造方法
和调用成员方法类似,不再做过多讲解。
public static void printStructureMethod(Object object) {
Class c = object.getClass();
// 获得类的名字,传入的是什么类型,就表示什么类型,而不是父类object类型。
System.out.println("类的名称:" + c.getName());
System.out.println("类的构造方法:");
Constructor[] constructors = c.getConstructors();
for (int i = 0; i < constructors.length; i++) {
Constructor constructor = constructors[i];
System.out.print(constructor.getName() + " (");
Class[] parameterTypes = constructor.getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
Class parameterType = parameterTypes[j];
if (j != 0)
System.out.print(" , ");
System.out.print(parameterType.getSimpleName());
}
System.out.println(")");
}
}
源代码的下载链接
CSDN下载链接:http://download.csdn.net/detail/d_inosaur/9855095
码云链接:https://gitee.com/D_inasour/codes/ursvnom912cghatek7q3z89#Reflex.rar