Java反射

        今天咱们来聊一聊Java中的反射;反射,即在程序运行时,可以动态的知道任意Class文件中包括私有的构造函数、变量、普通函数。

        一、获取class

如果我们想通过反射创建某个类的实例,那么我们需要先获取它的class,然后再创建对象。先创建一个普通的javabean。

获取class的方式一共有4种:

        1.通过java的class获取

    val personClass = Person::class.java

        2.通过javabean的全路径,注意上面javabean,我把package特意也贴上了

    val personClass = Class.forName("com.example.reflextest.Person")

        3.通过已创建的对象获取

    val person = Person("lisi", 104)
    val personClass = person.javaClass

        4.通过classloader

    val classLoader = this::class.java.classLoader
    val personClass = classLoader.loadClass("com.example.reflextest.Person")

其中第1种和第2种方式是经常使用到的。然后class创建对象,这里分2种方法

        二、通过反射创建对象

        1.直接用class创建

    val person = personClass.newInstance() as Person

        使用这种方式需要注意1点的是,它是通过javabean中的无参构造去创建的,所以要保证javabean中有无参构造,否则会出问题。

        2.通过class获取javabean的构造函数创建对象

我们可以通过class获取javabean中声明的所有构造函数:

    val constructors = personClass.constructors

    val constructors = personClass.declaredConstructors

这两种方式返回的都是构造函数的数组。可以看到constructors获取的是所有public的构造,而declaredConstructors获取的类中声明的所有构造。也可以单独获取某个构造函数,不过前提是我们要知道这个构造函数需要的参数,以2参的构造函数为例:

    val constructor = personClass.getConstructor(String::class.java,                           Int::class.java)
    //    constructor.isAccessible = true
    val person = constructor.newInstance("张三", 103) as Person
    Log.e("Main","person === $person")

这里有一行注释掉的代码,它的作用是在:如果调用的方法是private修饰的私有方法,则必须加上它,否则会提示我们不能调用。getConstructor的参数是调用它需要传入的参数类型。

打印结果:

person === Person(name=张三, age=103)

        三、获取类中的方法并调用

获取方法:

    val methods = personClass.methods
    val methods = personClass.declaredMethods

返回的都是Method数组,或获取某个具体方法

    val method = personClass.getMethod("print")
    val method = personClass.getDeclaredMethod("print")

获取方法是通过方法名和参数来获取的,获取print方法并调用

    val method = personClass.getDeclaredMethod("print")
    method.isAccessible = true
    method.invoke(person)

因为print方法是private修饰的所有要加上isAccessible = true,然后执行invoke调用函数的时候,需要将调用者传进去,说明是调用的这个对象的某某方法,就像平时调用某个对象的方法意思一样person.print()。但是,注意这里有个但是,如果调用的方法是静态的(被static修饰),则执行invoke不需要传入对象实例,可以传null。

        四、获取变量并赋值

获取变量对应的方法是

    val fields = personClass.fields
    val fields = personClass.declaredFields

通过上边的方法获取这里显然,返回的都是变量数组Filed[],获取某个变量

    val field = personClass.getField("gender")

传入变量的名称。

对field赋值

    field.isAccessible = true
    field.set(person, 3)

field.isAccessible就不再重复解释了;set方法,其实和调用方法时是一个意思,第一个参数,调用的谁?后边的参数则是要赋的值。如果是静态变量,第一个参数,谁,可以为null。

另外提一下Modifier这个类,个人理解它就是用来判断修饰符的,有兄弟说了:“isAccessible可以对private使用,public的并不需要啊,我有洁癖我就想在private的时候再使用”。那就可以用Modifier来搞,比如:

    val field = personClass.getField("gender")
    field.isAccessible = true
    field.set(person, 3)

javabean中的gender是private,我们可以用Modifier来判断gender字段的修饰符是否为某种修复时:

    val field = personClass.getDeclaredField("gender")
    if (field.modifiers == Modifier.PRIVATE) {
        Log.e("Main","is private")
        field.isAccessible = true
    }
    field.set(person, 3)

怎么样?没毛病吧,其实Modifier中有很多修饰符的定义,我们都可以用这个类来做判断等等操作,比如判断private static 2个关键字修饰的,它内部大部分常量及方法,这里就不贴出来了,感兴趣的伙伴可以自己点进去看一下源码。

在很多优秀的开源库里都用到了反射、动态代理等技术,比如retiofit;后边再整理一些关于代理和hook的文章,敬请期待。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值