在java或scala中是否有一种方法,允许以自动方式重写超类的方法?
免责声明:我不假装是一个有经验的程序员,请不要因为下面的任何编码暴行而杀了我。
我有一个类a的包装器B,它做一些事情并委托给a的两个不同实例。问题是,类a有非常多的方法。这是我最初的Java实现。这是一个有着大量重复代码的怪物。它可以工作,但可能包含许多错误,其中一些可能难以跟踪,其中一些只是会产生错误的结果而不被注意。
这是我第一次尝试使用scala结构类型重新实现。
def get(key: Array[Byte]): Array[Byte] = {
val f: (Transaction) => Response[Array[Byte]] = _.get(key)
wrap[Array[Byte]](f, redundancySwitch, currentDB, key).get()
}
剩下的留给通用换行函数。这已经很不错了!但我仍然需要单独具体地实现每个方法。
我的下一个想法是尝试有一个单一的(反射的)广义实现来复制到每个重写的方法体中,这样在函数对象f的定义中,将有一些东西填充当前调用方法的名称。
def get(key: Array[Byte]): Array[Byte] = {
val f: (Transaction) => Response[Array[Byte]] = _.someReflectionMagic.nameOfCurrentlyCallingMethod(args)
获取方法对象是可以的,但不知道如何将其传递给f,并且似乎没有办法获取和复制当前调用的方法的参数。这是我痛苦的尝试:
def zadd(key: String, score: Int, value: String) = {
// get the current Method
val thisMethod = new Object().getClass.getEnclosingMethod
val paramTypes = thisMethod.getParameterTypes
val returnType = thisMethod.getReturnType;
// this doesn't exist. how to reflectively forward parameter values (not parameter Types) into an Array for later reflective method invocation?
val params = thisMethod.getParameters
// I want to avoid to get it manually:
val params = new Array[Object]
params(0) = key
params(1) = score
params(2) = value
// this doesn't work. how to indicate the returnType here?
def f(t: Transaction): Response[returnType.class] =
t.getClass.getMethod(thisMethod.getName, paramTypes).
invoke(t,params).
asInstanceOf(Response[String])
wrap[String](f, redundancySwitch, currentDB, key).get()
}
private def getMethodName: String = {
val ste: Array[StackTraceElement] = Thread.currentThread.getStackTrace
return ste(2).getMethodName
}
这看起来很可怕,可能真的很可怕。你们这些专家,有什么办法能让它起作用吗?我希望至少意图是明确的?
这种方法仍然需要在包装器类中有>200个方法体。我想知道是否有任何方法可以完全不使用它:类B包装类A,从表面上看,B似乎拥有A的所有方法,甚至没有显式地实现它们。当B被A的方法x(args:T):U调用时,自动覆盖/自动委托给单个一般化方法B.y(x: T=>U)。Y()类似于第二个链接中的wrap()方法。然而,上述许多问题仍然存在……例如,如何捕获参数并将方法名称应用于结构类型值…
这有意义吗?这似乎不可能与Java/Java的反射。scala中有什么能帮到我的吗?也许是一些实验性的scala反射?
谢谢你的提示
一种方法是使用java.lang.reflect.Proxy。这将要求您为所有方法提供一个接口,但是您可以在Eclipse中使用Refactor->Extract interface相当容易地获得这个接口。
这将为您提供要在代理中实现的接口,并且您可以使用反射在InvocationHandler中调用A的正确实例。反射可能是一个潜在的性能问题。
From javadoc for Proxy:
动态代理类(下面简称为代理类)是类,该类实现在运行时指定的接口列表创建类,其行为如下所述。一个代理接口就是这样一种接口,它由代理类实现。一个代理实例是代理类的实例。每个代理实例具有关联的调用处理程序对象,该对象实现接口
InvocationHandler
。代理实例上的方法调用将通过其代理接口之一发送到invoke
实例的调用处理程序的方法,传递代理实例中,一个标识该方法的java.lang.reflect.Method
对象对象类型的数组,其中包含参数。调用处理程序处理编码的方法调用,它返回的结果将是作为代理实例上的方法调用的结果返回。
编辑:如果我正确理解你的问题,你有一个类B委托给a(或多个a)。您希望使用类B上定义的方法,并将它们全部重定向到单个方法。这正是代理所做的。它与接口一起工作,但是您可以很容易地在Eclipse中使用Extract interface获得一个接口。代理将实现该接口,并将对所有方法的所有调用重定向到InvocationHandler.invoke(),其中包含被调用的方法以及所使用的对象实例和参数。
在Scala中你可以写一个编译器插件。我觉得反射在这里帮不上什么忙。如果您只需要一种可以做到这一点的JVM语言,而且不一定是Scala,那么可以看看Groovy和它的@Delegate
注释。