开发者

Can I redefine String#length?

I'd like to re-implement a method of a Java class. For example, for "hi".length() to return 4.开发者_JS百科 (How) Can I do that?

I know using SomeClass.metaClass I can get a reference to an existing method and define new (or overriding) method, but I can't seem to be able to do that for existing Java methods.


Using Groovy, you can replace any method (even those of final classes) with your own implementation. Method replacement in Groovy uses the meta-object protocol, not inheritance.

Here's the example you requested, i.e. how to make String.length() always return 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


Seems like it could be possible by abusing String metaClass. But the attempt I've done so far in groovy console didn't led to the expected result :

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

println "hi".length()

outputs the sad 2

I think you could take a look at Proxy MetaClass or Delegating metaClass.


If you did redefine it, it would only work in Groovy code. Groovy can't change the way Java code executes.

In Groovy, "hi".length() is roughly equivalent to this Java:

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

Because Groovy doesn't actually call length directly, metaClass tricks work in Groovy code. But Java doesn't know about MetaClasses, so there is no way to make this work.


Although this question is very old I like to point out another way (at least for newer Groovy versions) . The length() method in java.lang.String is implemented from java.lang.CharSequence interface. In order to reimplement the method using the String-metaClass you need to "override" the method in the metaClass of the interface first.

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

The solution using String.metaClass.invokeMethod changes the behaviour of all String-methods and is problematic. For instance, simply invoking "asdf".size() leads to an exception on my setup.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜