可以使用Groovy元编程覆盖Java类上的私有方法吗
我试图使用元编程重写Java类上的私有方法。代码如下所示:
// Java class
public class MyClass{
private ClassOfSomeSort property1;
private ClassOfSomeOtherSort property2;
public void init(){
property1 = new ClassOfSomeSort();
property2 = new ClassOfSomeOtherSort();
doSomethingCrazyExpensive();
}
private void doSomethingCrazyExpensive(){
System.out.println("I'm doing something crazy expensive");
}
}
// Groovy class
public class MyClassTest extends Specification{
def "MyClass instance gets initialised correctly"(){
given:
ExpandoMetaClass emc = new ExpandoMetaClass( MyClass, false )
emc.doSomethingCrazyExpensive = { println "Nothing to see here..." }
emc.initialize()
def proxy = new groovy.util.Proxy().wrap( new MyClass() )
proxy.setMetaClass( emc )
when:
proxy.init()
then:
proxy.property1 != null
proxy.property2 != null
}
}
问题是没有调用doSomethingCrazyExpensive的重写实现——我认为这是因为私有方法是由init()方法在内部调用的,而不是通过元类调用的。如果我打电话给我的代理。doSomethingCrazyExpensive()直接调用重写的方法,因此元编程在一定程度上可以工作
有没有一种方法可以使用元编程来重写Java类(或实例)上的方法,从而在内部调用被重写的实现时调用它
# 1 楼答案
不能使用元类重写Groovy中从Java代码调用的方法
这就是为什么不能在Java中“模拟”对这个私有方法的调用:它是由Java类本身调用的,而不是从Groovy调用的
当然,如果您的类是用Groovy编写的,那么这个限制就不适用了
如果可以的话,我建议您重构Java类,这样您就可以使用普通方法来模拟昂贵的方法调用。或者甚至使该方法受到保护,然后在子类中重写它
# 2 楼答案
似乎无法使用Groovy元编程来替换Java类的方法——甚至是公共方法——请在Groovy控制台中尝试以下方法来确认:
如果您可以修改
MyClass
的源代码,我会使doSomethingCrazyExpensive
受到保护,或者更好地重构它,使其更易于测试在进行上述更改之后,当测试
MyClass
时,您可以使用CrazyExpensive
的模拟/存根实现轻松地实例化它# 3 楼答案
我无意中发现了这个问题,并认为我应该提供一个不同的答案:是的,你可以覆盖一个现有的方法——你只需要将meta类更改为ExpandoMetaClass
例如,当您添加第一个方法时,会自动发生这种情况
下面是一个例子:
结果是:
您可以看到,添加fum方法后,元类变为expando。现在,当试图覆盖原始的foo时,它就起作用了
# 4 楼答案
Groovy
as
操作符功能非常强大,可以用Java中可见的具体类型创建代理。遗憾的是,它似乎无法覆盖私有方法,尽管我设法更改了一个公共方法:Java类:
Groovy测试:
它打印:
因此,公共方法被截获和更改,即使是在从Java调用时,但不是私有方法