如何重载整个超类?方法,显式的还是隐式的?
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 调用时,自动覆盖/自动委托给单个通用方法 By(x: T=>U)。 y() 类似于第二个链接中的wrap() 方法。然而,上述许多问题仍然存在......即如何捕获参数并将方法名称应用于结构类型值......
这有意义吗? 这对于Java/java的反射来说似乎是不可能的。 scala 有什么可以帮助我的吗?也许是一些实验性的 scala 反射?
非常感谢您的任何提示
Is there a way in java or scala, that allows to override methods of the super class in an automated fashion?
Disclaimer: i don't pretend to be an experienced programmer, please don't kill me for any coding-atrocities below.
I have a wrapper B of class A that does some stuff and delegates to two different instances of A. Problem is, class A has a very big number of methods. Here is my original Java implementation. It's a monster with enormous code duplication. It works but probably contains a lots of errors, some of which maybe hard to track, some of them just will produce wrong results unnoted.
Here is my first try of a reimplementation 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()
}
the rest is left to the common wrap function. This is already nice! But I'd still need to implement each single method individually and specifically.
My next thought was to try to have a single (reflective) generalized implementation to copy into each overriding method body, such that in definition of the function object f, there would be something to fill in the name of currently calling method.
def get(key: Array[Byte]): Array[Byte] = {
val f: (Transaction) => Response[Array[Byte]] = _.someReflectionMagic.nameOfCurrentlyCallingMethod(args)
Getting the method object is ok, but not how to pass it to f, and there doesn't seem to be a way to get and copy the arguments of the currently called method. Here's my aching attempt:
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
}
this looks horrible and probably really is horrible. You experts, is there anything that could make it work? I hope at least the intention is clear?
This approach would still require having those >200 method bodies in my wrapper class. I wonder if there is any way to completely go without that:
A class B wrapping class A, that looks to the outside as if B had all methods of A, without even explicitely implementing them. When B is invoked by an A's method x(args:T):U, auto-override / auto-delegate to a single generalized method B.y(x: T=>U).
y() would be something like the wrap() method in the second link. However, many of the above problems remain... i.e. how to capture the arguments and apply the method name on a structural typed value...
does this make sense?
This doesn't seem to be possible with Java / java's reflection. Is there anything in scala that could help me? Maybe some experimental scala reflection?
thanks a lot for any hints
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一种方法是使用 java.lang.reflect .代理。虽然这需要您为所有方法提供一个接口,但您可以使用 Eclipse 中的 Refactor->Extract Interface 轻松获得此接口。
这将为您提供在代理中实现的接口,并且您可以在 InitationHandler,使用反射。反射可能是潜在的性能问题。
来自代理的 javadoc:
编辑:如果我正确理解你的问题,你有一个 B 类委托给 A (或多个 As)。您希望采用类 B 上定义的方法并将它们全部重定向到单个方法。这正是代理所做的事情。它与接口一起工作,但是您可以使用 Eclipse 中的 Extract Interface 轻松获得一个接口。 Proxy 将实现该接口,并将对所有方法的所有调用重定向到 InvocableHandler.invoke() 以及所调用的方法以及所使用的对象实例和参数。
One way would be to use java.lang.reflect.Proxy. This would require you to have an interface for all of your methods though, but you can get this reasonably easily using Refactor->Extract Interface in Eclipse.
This will give you the interface to implement in your Proxy, and you call the correct instance of A in your InvocationHandler, using reflection. The reflection may be a potential performance problem.
From the javadoc for Proxy:
EDIT: If I understand your problem correctly, you have a class B which delegates to A (or multiple As). You want to take the methods defined on class B and have them all redirect to a single method. This is exactly what a Proxy does. It works with interface, but you can get one easily enough with Extract Interface in Eclipse. The Proxy will implement that interface and redirect all calls to all methods to InvocationHandler.invoke() with the method that was called along with the instance of the object and parameters that were used.
在 Scala 中,您可以编写编译器插件。我认为反思在这里对你没有多大帮助。如果您只需要一种可以执行此操作的 JVM 语言,并且不必是 Scala,请查看 Groovy 及其
@Delegate
注释。In Scala you could write a compiler plugin. I don't think reflection can help you much here. If you just need a JVM language which can do this, and it doesn't have to be Scala, take a look at Groovy and its
@Delegate
annotation.