如何重载整个超类?方法,显式的还是隐式的?

发布于 2024-12-08 17:45:22 字数 2361 浏览 0 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

高速公鹿 2024-12-15 17:45:22

一种方法是使用 java.lang.reflect .代理。虽然这需要您为所有方法提供一个接口,但您可以使用 Eclipse 中的 Refactor->Extract Interface 轻松获得此接口。

这将为您提供在代理中实现的接口,并且您可以在 InitationHandler,使用反射。反射可能是潜在的性能问题。

来自代理的 javadoc:

动态代理类(下面简称代理类)是一个
实现运行时指定的接口列表的类
该类已创建,其行为如下所述。代理
接口就是这样一个由代理类实现的接口。一个
代理实例是代理类的实例。每个代理实例
有一个关联的调用处理程序对象,它实现
接口InplicationHandler。代理实例上的方法调用
通过其代理接口之一将被分派到invoke
实例调用处理程序的方法,传递代理
实例,一个标识方法的java.lang.reflect.Method对象
被调用的对象,以及包含对象类型的数组
论据。调用处理程序处理编码方法
适当调用,它返回的结果将是
作为代理实例上的方法调用的结果返回。

编辑:如果我正确理解你的问题,你有一个 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:

A dynamic proxy class (simply referred to as a proxy class below) is a
class that implements a list of interfaces specified at runtime when
the class is created, with behavior as described below. A proxy
interface is such an interface that is implemented by a proxy class. A
proxy instance is an instance of a proxy class. Each proxy instance
has an associated invocation handler object, which implements the
interface InvocationHandler. A method invocation on a proxy instance
through one of its proxy interfaces will be dispatched to the invoke
method of the instance's invocation handler, passing the proxy
instance, a java.lang.reflect.Method object identifying the method
that was invoked, and an array of type Object containing the
arguments. The invocation handler processes the encoded method
invocation as appropriate and the result that it returns will be
returned as the result of the method invocation on the proxy instance.

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.

看轻我的陪伴 2024-12-15 17:45:22

在 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文