- JDK动态代理中的问题——调用proxy的toString方法引起的栈溢出
- kotlin反射
- 示例
- Exception in thread “main” java.lang.IllegalArgumentException: wrong number of arguments
val ob: Any = method!!.invoke(obj, *(args ?: arrayOfNulls<Any>(0))) // 使用传播运算符达到和java多参数相同的效果
* 数组对象 :kotlin的spread 操作符,
* 解释:When we call a vararg-function, we can pass arguments one-by-one, e.g. asList(1, 2, 3), or, if we already have an array and want to pass its contents to the function, we use the spread operator (prefix the array with *):
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
动态反射主要是,使用接口调用接口方法去对应的实现类执行接口的方法
- 设置接口类
interface People {
fun work(): String
}
- 实现接口
public class Student implements People {
@NotNull
@Override
public String work() {
Log.d("ls", "努力学习");
return "学生的工作是学习";
}
}
3.InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法
class WorkHandler(var obj: Any): InvocationHandler {
var target: Any? = null
fun newProxy(tar: Any): Any {
target = tar
return Proxy.newProxyInstance(this.javaClass.classLoader, target?.javaClass?.interfaces, this)
}
/**
* proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
* method:我们所要调用某个对象真实的方法的Method对象
* args:指代代理对象方法传递的参数
*
* throws Throwable
*/
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
return try {
//在真实的对象执行之前我们可以添加自己的操作
Log.d("ls", "before invoke。。。")
// Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
// 为什么Kotlin在使用代理时抛出IllegalArgumentException : https://stackoverflow.com/questions/41774450/why-is-kotlin-throw-illegalargumentexception-when-using-proxy
val ob: Any = method!!.invoke(obj, *(args ?: arrayOfNulls<Any>(0))) // 使用传播运算符达到和java多参数相同的效果
//在真实的对象执行之后我们可以添加自己的操作
Log.d("ls", "after invoke。。。")
ob
} catch (t: Throwable) {
t.message!!
} finally {
Log.d("ls", "执行完成")
}
}
}
- 测试
//要代理的真实对象
val p: People = Student()
//代理对象的调用处理程序,我们将要代理的真实对象传入代理对象的调用处理的构造函数中,最终代理对象的调用处理程序会调用真实对象的方法
val handler: InvocationHandler = WorkHandler(p)
/**
* 通过Proxy类的newProxyInstance方法创建代理对象,我们来看下方法中的参数
* 第一个参数:people.getClass().getClassLoader(),使用handler对象的classloader对象来加载我们的代理对象
* 第二个参数:people.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,这样代理对象就能像真实对象一样调用接口中的所有方法
* 第三个参数:handler,我们将代理对象关联到上面的InvocationHandler对象上
*/
val proxy = Proxy.newProxyInstance(handler.javaClass.classLoader, p.javaClass.interfaces, handler) as People
Log.d("ls", proxy.work())