PS:这里编写是用的Kotlin,相信只会Java也能看懂
背景
众所周知Java里的反射是一件非常枯燥繁琐的事情,特别是遇到a.a.c.v.b.a这类的,如果要完全写出Java代码就会非常的麻烦,而且反射写得多会把自己绕进去,导致出现问题
传统编写方式
假设原始的代码的反射如下
val fieldB = XXXX::class.java.getDeclaredField("b")
fieldB.isAccessible = true
val b = fieldB.get(XXX) ?: return@delay
val fieldBA =com.xxx.b.d::class.java.getDeclaredField("C")
fieldBA.isAccessible = true
//((com.XXX.a.a) b.a)
val a = fieldBA.get(b) ?: return@delay
a as com.XXX.a.a
val fieldBAA = com.XXX.a.a::class.java.getDeclaredField("a")
fieldBAA.isAccessible = true
val title = fieldBAA.get(a) ?: return@delay
通过多层嵌套才成功获得我们想要的变量的值,但是这才3层就已经很多代码了,而且反射的时候是不需要强转的。
循环反射
我们发现上面很多的重复代码所以可以使用for循环代替,具体实现代码如下
fun fieldQueue(fieldobj: Any, result: (obj: Any) -> Unit, vararg rule: String) {
val count = rule.size
var tempFieldClz: Class<*> = fieldobj.javaClass
var tempFieldobj: Any = fieldobj
for (index in 0 until count) {
val tempField = tempFieldClz.getDeclaredField(rule[index])
tempField.isAccessible = true
tempFieldobj = tempField.get(tempFieldobj) ?: return
tempFieldClz = tempFieldobj.javaClass
}
result(tempFieldobj)
}
其中的 result: (obj: Any) -> Unit
其实就是一个回调,在Kotlin里面的语法糖就是如此vararg
对应的就是Java里面的...
(可变参数) class<*>
就是class<?>
通过上述代码,我们可以用以下代码来实现
fieldQueue(XXXX, {it->
LogUtils.e("XXXe", it)
}, "b", "C", "a")
实验证明,只需要很精简的代码就可以实现复杂的嵌套反射
前提是:规则一定要对,一个string就对应一个Field!
如果帮到您,欢迎点个赞哦