groovy 我可以重新定义String#length吗?

pu82cl6c  于 2022-12-03  发布在  其他
关注(0)|答案(4)|浏览(180)

我想重新实现一个Java类的方法。例如,让"hi".length()返回4。(如何)我能做到吗?
我知道使用SomeClass.metaClass我可以获得对现有方法的引用并定义新的(或覆盖)方法,但我似乎不能对现有的Java方法做到这一点。

jchrr9hc

jchrr9hc1#

使用Groovy,你可以用你自己的实现替换任何方法(甚至final类的方法)。Groovy中的方法替换使用元对象协议,而不是继承。
下面是您请求的示例,即如何使String.length()始终返回4

// Redefine the method
String.metaClass.invokeMethod = { name, args ->

    def metaMethod = delegate.metaClass.getMetaMethod(name, args)
    def result = metaMethod.invoke(delegate, args)

    name == 'length' ? 4 : result
}

// Test it
assert "i_do_not_have_4_chars".length() == 4
krugob8w

krugob8w2#

看起来像是可以通过abusing String metaClass来实现的。但是到目前为止我在groovy控制台中所做的尝试并没有产生预期的结果:

def oldLength = String.metaClass.length
String.metaClass.length = { ->
    return oldLength+10;
}

println "hi".length()

输出SAD 2
我想你可以看看Proxy MetaClassDelegating metaClass

z9zf31ra

z9zf31ra3#

如果你重新定义了它,它只能在Groovy代码中工作,Groovy不能改变Java代码的执行方式。
在Groovy中,"hi".length()大致相当于下面的Java:

stringMetaClass.invokeMethod("hi","length");

因为Groovy实际上并不直接调用length,所以MetaClass技巧在Groovy代码中是有效的,但是Java不知道MetaClass,所以没有办法让它工作。

hfsqlsce

hfsqlsce4#

虽然这个问题已经很老了,但我还是想指出另一种方式(至少对于较新的Groovy版本来说是这样)。java.lang.String中的length()方法是从java.lang.CharSequence接口实现的。为了使用String-metaClass重新实现该方法,您需要首先“覆盖”接口的metaClass中的方法。

CharSequence.metaClass.length = { -> -1}
String.metaClass.length = { -> 4 }
assert "i_do_not_have_4_chars".length() == 4

使用String.metaClass.invokeMethod的解决方案改变了所有String方法的行为,存在问题。例如,简单地调用"asdf".size()会导致我的设置出现异常。

相关问题