Reflect的简单使用。
如果一个类当中的变量和方法为私有时,我们在其它地方就无法通过新建这个类的实例来获取它,这时候就可以采用Reflect(反射)机制来解决这个问题。通过反射我们能够获取某个类中的私有成员。
背景:
Android新人,听任神说自己学会的东西要写出来,有利于自己梳理和使用。
在学习师兄代码的时候,遇到了Reflect这个东西,一开始看到的时候,Class、Field、method完全看不懂,只能百度,然后看到了这位前辈(hfreeman2008)的博客里讲了这个知识点,于是学习了,不过前辈的代码有点长,我在学习的时候精简了这个例子,并有一些地方采用了不同的做法,看起来更为简单,希望能够帮助到同样第一次接触到Reflect的朋友们(因为转载需要向前辈申请,所以我这里就没有转载和贴链接了,不太懂这些。。。)。
方法:
1.创建一个目标对象的实例(myClass),然后赋给一个新的Class对象(clazz)。
2.通过Field/Method来获取到目标类中的变量(aInt)或方法(setInt(int aInt))。
3.将Field/Method.setAccessible属性设置为true。
4.通过field.get(myClass)来获取变量,通过method.invoke(myclass)来执行方法。
代码如下:
MyClass.java
package com.example.qicaizi.reflecttest2;
import android.util.Log;
/**
* Created by qicaiZI on 2017/7/29.
*/
public class MyClass {
private static final String TAG = "MyClass";
private int aInt = 0;
private boolean bBoolean = false;
private String sString = "test";
public MyClass() {
Log.d(TAG, "public MyClass Constructor");
}
public MyClass(int aInt, boolean bBoolean, String sString) {
Log.d(TAG, "private MyClass Constructor");
this.aInt = aInt;
this.bBoolean = bBoolean;
this.sString = sString;
}
private void setInt(int aInt) {
int pre = this.aInt;
this.aInt = aInt;
Log.d(TAG, "private setInt,aInt: " + pre + " to " + this.aInt);
}
private void getAll() {
Log.d(TAG, "private getAll()");
Log.d(TAG, "aInt: " + aInt + " bBoolean: " + bBoolean + " sString: " + sString);
}
}
MainActivity.java
package com.example.qicaizi.reflecttest2;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private MyClass myClass;
//Reflect相关对象
private Class clazz;
private Method method,method2;
private Field aInt, bBoolean, sString;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个目标类的实例(myClass),然后赋给一个新的Class对象(clazz)。
myClass = new MyClass();
clazz = myClass.getClass();
try {
//通过Method来获取目标类中我们想要的私有方法
//访问getAll方法,这里只能使用getDeclaredMethod。getMethod会报错
method2 = clazz.getDeclaredMethod("getAll");
method2.setAccessible(true);
method2.invoke(myClass);
//通过Field来获取目标类中我们想要的私有变量,这里也只能使用getDeclaredField
aInt = clazz.getDeclaredField("aInt");
aInt.setAccessible(true);
//这里打印结果不是预期中的MyClass中的初始化值0,而是指向"aInt"变量的一个路径
Log.d(TAG, "aInt: " + aInt);
//所以我们用aInt.get(myClass)来获取它的值,这里获取到的是object型,不是int。打印结果为0
Log.d(TAG, "aInt: " + aInt.get(myClass));
//这里我们就可以用Field自带的方法来操作了,用Field.set方法可以改变获取到的变量的值。打印结果为1
aInt.setInt(myClass, 1);
Log.d(TAG, "aInt: " + aInt.get(myClass));
//如果目标类中私有方法包括参数,如MyClass中的setInt(int aInt),
//那么这里传入相应的("方法名", ***.class)就可以了
method = clazz.getDeclaredMethod("setInt", int.class);
method.setAccessible(true);
//用method.invoke来执行MyClass中的setInt方法。再打印一次,结果为2
method.invoke(myClass, 2);
Log.d(TAG, "aInt" + aInt.get(myClass));
//最后再调用一次getAll,前面用method2获取,此处不必重新获取
method2.invoke(myClass);
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印结果
PS:只是作为梳理,也希望能够帮到人,千万别喷我。。。