java/android中的反射机制

Ps:最近在研究热修复技术,其中用到了反射机制,所以复习一下,做个记录。

什么是反射机制

个人理解就是通过反编译获取类中所有的信息(包括:变量、方法、接口),供开发者利用。

优缺点

  • 优点:增强代码的自适应能力(动态的创建对象)、调用一些类中的私有方法(例如通过反射机制调用android系统挂断电话的方法)。

  • 缺点:降低程序性能。牛逼的背后总是苦逼,反射机制说白了就是通过类名去解释类,然后告诉jvm我们需要做什么,肯定比jvm执行固定代码要耗时耗资源。

常用的几个类

api文档中反射所用到的所有类

image

ps:这里不讲反射机制中的代理Proxy,因为水平有限,仅仅介绍下面几个类

  1. Class:由虚拟机自动构建,表示正在运行的java程序中的类或接口(下面几个类对象基本都是通过Class类获取的)。

  2. Method:从类中获取的方法,获取方法后通过method.invoke(…)执行

  3. Field:从类中获取的成员变量

  4. Constructor:从类中获取的构造方法

  5. Array:处理通过返回获取的数组(测量长度、修改数组等等)

  6. Modifier:获取的方法或变量的修饰符(method.getModifiers()获取,如:private,public..)

这几个类的api也很简单,基本通过方法名就能理解,不在赘述。

一个Demo讲解用法

Ps:本例通过反射Date类,实现获取当前时间,即:当前的毫秒数,同System.currentTimeMillis()效果一样

//获取Date类的运行时类,Class的获取方法有3种
//1. xxx.class() ;
//2. xxx.forName("java.util.Date") ;  //通过全类名
//3. XXX xxx = new XXX(); xxx.class() ;
Class c = Date.class;

//获取Date所有声明的方法包括private类型的,但不包括父类的方法
//可以通过 c.getMethods()---获取包括父类的所有public方法,但不包括private类型方法
Method[] ms = c.getDeclaredMethods();

for (Method m : ms) {
   //获取方法需要传入的参数
   Type[] types = m.getGenericParameterTypes();
   StringBuilder builder = new StringBuilder();
   builder.append("(");
   for (Type type : types) {
        builder.append(type.toString() + ",");
   }
   int last = builder.lastIndexOf(",");
   if (last > 0) {
      builder.deleteCharAt(last);
   }
  builder.append(")");
  //获取方法的修饰类型(private、public等)
  String modifier = Modifier.toString(m.getModifiers()) ;
  //获取方法的返回类型
  String rType = m.getGenericReturnType().toString() ;
  System.out.println(modifier + " " + rType + " " + m.getName() + builder.toString());
}

image

通过上面的代码,可以获取Date类的所有方法,上图只截取了部分,其中有个用红色方框标记的方法,是私有的,通过源码可以知道,此方法可以得到当前时间的毫秒数,我们可以通过反射机制,调用这个方法,达到获取当前毫秒数的目的


Class c = Date.class;
//通过Class实例化一个Date类对象
Object o = c.newInstance();
//通过上例红方框中的方法名,得到该方法的实例
Method m = c.getDeclaredMethod("getTimeImpl");
//设置jvm不检测此方法的访问权限(相当于暴力破除private)
m.setAccessible(true);
//调用getTimeImpl()方法
long l = (long) m.invoke(o, null);
System.out.println("currentTime:" + System.currentTimeMillis());
System.out.println("getTimeImpl:" + l);

执行结果:

这里写图片描述

Ps:其实这个例子并没有什么实际意义,只简单说明java反射机制的一些作用,可以调用系统不对开发者开发的功能,如果用自己写的类演示,没有丝毫意义。

再说Array

Array是反射机制中对数组的操作

//我们获取TestArray类的所有成员变量,并修改data数组
public class TestArray {

    private String str ;

    public long time ;

    private int[] data = new int[]{1,2,3,4,5} ;

    public int[] getData(){
       return data ;
    }

}

//获取TestArray类的所有成员变量,和获取Method基本一致,不在编写注释
Class c = TestArray.class;
Field[] fields = c.getDeclaredFields() ;
for (Field field : fields) {
    String mdf = Modifier.toString(field.getModifiers()) ;
    String type = field.getGenericType().toString() ;
    String name = field.getName() ;
    System.out.println(mdf+" "+type +" "+name);
}

//修改TestArray类中的data数组
//新建对象
TestArray ta = new TestArray() ;
System.out.println("修改之前的第三个数:"+person.getData()[2]);
//获取TestArray的Class
Class c1 = ta.getClass() ;
//获取data成员变量
Field m = c1.getDeclaredField("data") ;
//抑制jvm检测访问权限
m.setAccessible(true);
//回去data成员变量值
Object o = m.get(ta) ;
//判断data是否为数组
if(o.getClass().isArray()){
  //打印数组长度
  System.out.prinln("数组长度:"+Array.getLen(o)) ;
  //反射机制中,用Array类完成对反射数组的操作,将data数组中的第三个数改为77
   Array.set(o,2,77);
}
System.out.println("修改之后的第三个数:"+person.getData()[2]);

结果:

这里写图片描述

android中2个反射机制的应用实例

android中对反射机制应用非常广泛,比如:热修复、电话挂断。

  • 热修复:通过反射机制将生成的补丁”dex”,插入到DexPathList类的private Element[] dexElements数组的最前端,是系统查找类的时候,先找到补丁”dex”中的类,从而实现热修复的效果。ps:DexPathList是不对开发者开发的,连实例对象都获取不了,只能通过反射机制做到。

  • 电话挂断:通过android系统源码可知道,挂断电话需要调用ITelephony类的endCall()方法,系统是不对我们开放的,所有也需要通过发射机制调用endCall方法。\

  • 热修复中用到的反射机制代码,会在研究热修复的时候贴出,而反射机制挂断电话,网上有太多例子,这里就不做搬运工了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值