反射的简单使用
前置条件三个类:A 、B:A、C;
目标:分别在获取 B 和 C 中获取 A 的 私有变量 以及 调用私有方法
1. 三个类
- A:
package mm.chenme.lib.commutillibdemo.ui.other
open class A {
private val v1 = 100
private val v2 = "reflex"
companion object {
@JvmStatic
private fun printStatic(): String {
println("Hello reflex in static!")
return "execute complete!\n"
}
}
private fun printNoParam(): String {
println("Hello reflex without param!")
return "execute complete!\n"
}
private fun printHasParams(param1: String, param2: Int): String {
println("Hello reflex with params. param1:$param1, param2:$param2")
return "execute complete!\n"
}
}
- B:
class B : A()
- C:
class C
2. 步骤:
- 获取类 A 的 class,提供以下两种方法;
val clz = A::class.java
val clz = Class.forName("mm.chenme.lib.commutillibdemo.ui.other.A")
1. 操作私有变量:
- 获取 A 的成员变量;
val field = clz.getDeclaredField("v2")
- 修改访问权限;
field.isAccessible = true
- 获取
v2
的值并打印;
println(field.get(this) as String)
// 执行结果:
// reflex
- 设置
v2
的值并打印;
field.set(this, "Hello reflex!\n")
println(field.get(this) as String)
// 执行结果:
// Hello reflex!
2. 获取私有函数并执行:
- 获取函数;
val method = clz.getDeclaredMethod("printStatic")
getDeclaredMethod()
函数源码public Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { return getMethod(name, parameterTypes, false); }
name
:要获取的函数函数名称
parameterTypes
:要获取的函数参数类型的列表(对于无参的函数,该可变参数不写)
- 修改访问权限;
method.isAccessible = true
- 执行该函数并打印返回值;
println(method.invoke(null) as String)
// 执行结果:
// Hello reflex in static!
// execute complete!
invoke()
函数源码public native Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
obj
:被反射 class 的实例或其子类的实例(当函数为静态函数时,可以传null
);invoke 函数参数1可传的的数据类型为:
① clz 的实例;
② clz 子类的实例;
③ null;
args
:函数所对应的参数(对于无参的函数,该可变参数不写)
3. 类 B 的完整代码
class B : A() {
fun reflexVariable() {
val clz = A::class.java
val field = clz.getDeclaredField("v1")
field.isAccessible = true
println(field.get(this) as Int)
val field2 = clz.getDeclaredField("v2")
field2.isAccessible = true
println(field2.get(this) as String)
field2.set(this, "Hello reflex!\n")
println(field2.get(this) as String)
}
fun reflexMethod() {
val clz = A::class.java
/**
* 静态无参数函数反射
* invoke 函数参数1可传的的数据类型为:
* ① clz 的实例;
* ② clz 子类的实例;
* ③ null
*/
val method = clz.getDeclaredMethod("printStatic")
method.isAccessible = true
println(method.invoke(null) as String)
/**
* 普通无参数函数反射
* invoke 函数参数1可传的的数据类型为:
* ① clz 的实例;
* ② clz 子类的实例;
*/
val method1 = clz.getDeclaredMethod("printNoParam")
method1.isAccessible = true
println(method1.invoke(this) as String)
/**
* 带有参数的函数反射
*/
val method2 = clz.getDeclaredMethod("printHasParams", String::clas
method2.isAccessible = true
println(method2.invoke(this, "arg1", 100) as String)
}
}
- 调用
reflexVariable()
和reflexMethod()
执行结果
100
reflex
Hello reflex!
Hello reflex in static!
execute complete!
Hello reflex without param!
execute complete!
Hello reflex with params. param1:arg1, param2:100
execute complete!
4. 在类 C 中使用反射
- 操作变量时,将
get() set()
中的实例参数改为clz.newInstance()
即可;
println(field.get(this) as Int)
field2.set(this, "Hello reflex!\n")
// 改为
println(field.get(clz.newInstance()) as Int)
field2.set(clz.newInstance(), "Hello reflex!\n")
- 在执行函数时,将
invoke()
中的实例参数改为clz.newInstance()
即可;
println(method1.invoke(this) as String)
println(method2.invoke(this, "arg1", 100) as String)
// 改为
println(method1.invoke(clz.newInstance()) as String)
println(method2.invoke(clz.newInstance(), "arg1", 100) as String)