java或scala中有没有办法允许以自动方式覆盖超类的方法?
免责声明:我不假装自己是一位经验丰富的程序员,请不要因为下面的任何编码暴行而杀了我。
我有一个A类包装器B,可以完成一些事情并委托给两个不同的A实例。问题是,A类有很多方法。这是我的original Java implementation。这是一个庞大的代码重复的怪物。它可以工作,但可能包含很多错误,其中一些可能难以跟踪,其中一些只是会产生错误的结果。
这是我第一次尝试重新实现using scala structural typing。
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的所有方法,甚至没有明确地实现它们。当A的方法x(args:T)调用B时:U,自动覆盖/自动委托给单个广义方法B.y(x:T => U)。 y()类似于第二个链接中的wrap()方法。但是,上述许多问题仍然存在......即如何捕获参数并将方法名称应用于结构类型值......
这有意义吗? 使用Java / java的反射似乎无法做到这一点。 scala中有什么可以帮助我吗?也许是一些实验性的斯卡拉反射?
非常感谢任何提示
答案 0 :(得分:3)
一种方法是使用java.lang.reflect.Proxy。这需要您拥有所有方法的接口,但是您可以使用Eclipse中的Refactor-> Extract Interface轻松地实现这一点。
这将为您提供在代理中实施的界面,并使用反射在InvocationHandler中调用正确的A实例。反思可能是潜在的性能问题。
来自代理的javadoc:
动态代理类(下面简称为代理类)是一个 实现运行时指定的接口列表的类 创建类,其行为如下所述。代理人 interface是由代理类实现的接口。一个 代理实例是代理类的实例。每个代理实例 有一个关联的调用处理程序对象,它实现了 界面
InvocationHandler
。代理实例上的方法调用 通过其中一个代理接口将被分派到invoke
实例的调用处理程序的方法,传递代理 实例,标识方法的java.lang.reflect.Method
对象 被调用的,以及包含的类型为Object的数组 参数。调用处理程序处理编码的方法 适当的调用和它返回的结果 作为代理实例上的方法调用的结果返回。
编辑:如果我正确理解你的问题,你有一个B级代表A(或多个As)。您想要采用B类中定义的方法,并将它们全部重定向到单个方法。这正是代理所做的。它适用于界面,但您可以使用Eclipse中的Extract Interface轻松获得一个界面。 Proxy将实现该接口,并使用所调用的方法以及所使用的对象和参数的实例将对所有方法的所有调用重定向到InvocationHandler.invoke()。
答案 1 :(得分:1)
在Scala中你可以write a compiler plugin。我不认为反思可以帮助你。如果您只需要一个可以执行此操作的JVM语言,并且它不必是Scala,请查看Groovy及其@Delegate
注释。