我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情
反射概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
这里需要说到Java有两种对象,一个是Class对象,也就是类对象,还有一个是实例对象。实例对象就是通过Class对象创建出来的。
而反射就是针对Class对象进行的处理。
获取Class对象
我们知道java代码运行时,需要首先将java代码编译成二进制字节码,保存在.class文件中,然后JVM将.class文件载入内存,并且创建一个对应的Class对象。
获取Class对象有以下三种方式:
1、通过类名获取Class
Class userClass = User.class;
2、通过实例对象获取Class
User user = new User();
Class userClass = user.getClass();
3、通过完成类名路径获取Class
try {
Class userClass = Class.forName("com.androidwind.demo.reflection.User");
} catch (ClassNotFoundException e) {
Log.e(TAG, e.toString());
}
通过Class对象获取实例对象
Class userClass = Class.forName("com.androidwind.demo.reflection.User");
Object useObj = userClass .getConstructor().newInstance();
通过Class对象获取类所有方法
//获取Class对象
Class userClass = Class.forName("com.androidwind.demo.reflection.User");
//获取所有共有方法
userClass.getMethods();
Method[] methodArray = userClass.getMethods();
for(Method m : methodArray){
System.out.println(m);
}
//获取私有、受保护、默认方法
methodArray = userClass.getDeclaredMethods();
for(Method m : methodArray){
System.out.println(m);
}
//获取公有方法并调用
Method m = userClass.getMethod("setName", String.class);
Object obj = userClass.getConstructor().newInstance();
m.invoke(obj, "王五");
//获取私有方法并调用
m = userClass.getDeclaredMethod("setAge", int.class);
m.setAccessible(true);
Object result = m.invoke(obj, 20);
通过Class对象获取类所有属性
//获取Class对象
Class userClass = Class.forName("com.androidwind.demo.reflection.User");
//获取公有字段
Field[] fieldArray = userClass.getFields();
for(Field f : fieldArray){
System.out.println(f);
}
//获取私有、受保护、默认字段
fieldArray = userClass.getDeclaredFields();
for(Field f : fieldArray){
System.out.println(f);
}
//获取共有字段并赋值
Field f = userClass.getField("name");
Object userObj = userClass.getConstructor().newInstance();
f.set(userObj, "张三");
//获取私有字段并赋值
f = userClass.getDeclaredField("age");
f.setAccessible(true);
f.set(obj, 18);
扩展:反射与Annotation
通过反射获取的Method有两个关于Annotation的属性:
isAnnotationPresent:判断Annotation是不是某个类型;
getAnnotation:获取Annotation的值;
比如android-tiny-bus项目:
通过Subscriber这个Annotation标注threadMode是一个后台线程接收。
@Subscriber(threadMode = ThreadMode.BACKGROUND)
public void onEvent(TestBackgroundEvent event) {
System.out.println("[onEvent]Current thread id is: " + Thread.currentThread().getId());
if (isMainThread()) {
((TextView) findViewById(R.id.tv_hello)).setText("update in main thread");
} else {
((TextView) findViewById(R.id.tv_hello)).setText("update in background thread");
}
}
注册的时候会通过反射方法获取Annotation:
@Override
public void register(Object object) {
if (object == null) return;
Class cls = object.getClass();//获取类实例(即类信息)
Method[] methods = cls.getDeclaredMethods();//获取类实例的public方法
for (Method method : methods) {
if (method.isAnnotationPresent(Subscriber.class) &&//判断方法是否是Subscriber注释
method.getParameterTypes() != null//获取方法的传入参数类型
&& method.getParameterTypes().length == 1) {//只有一个参数
TinyHandler tinyHandler = new TinyHandler();
tinyHandler.setMethodName(method.getName());
tinyHandler.setObject(object);
Subscriber subscriber = method.getAnnotation(Subscriber.class);
System.out.println("subscriber = " + subscriber.threadMode());
tinyHandler.setThreadMode(subscriber.threadMode());
TinyBusManager.getInstance().add(method.getParameterTypes()[0], tinyHandler);
}
}
}