问题描述
我对groovys方法重载行为有些困惑:给定类
并在下面进行测试,我很满意 testAStringNull
和 testBStringNull
抛出不明确的方法调用异常,但为什么不是
testANull
和 testBNull
then?
更重要的是:为什么 testBNull(null)
call String foo(A arg)
?我猜这个对象不知道它所绑定的变量的类型,但为什么这个调用不会模糊,而其他的都是常规?
(我希望我解释得很清楚,我的头因创建这个最小
例子而感到痛苦。)
class Foo {
静态类A {}
静态类B {}
字符串foo(A arg){返回'a'}
字符串foo(String s,A a ){return'a'}
String foo(B arg){return'b'}
String foo(String s,B b){return'b'}
测试:
import org.junit.Test
import Foo.A
import Foo.B
class FooTest {
Foo foo =新的Foo()
@Test
void testA(){
A a = new A()
assert foo.foo(a)=='a'
@Test
void testAString(){
A a = new A()
assert foo.foo('fo o',a)=='a'
}
@Test()
void testANull(){
A a null =
assert foo .foo(a)=='a'
}
@Test
testAStringNull(){
a a = null
assert foo.foo ('foo',a)=='a'
}
@Test
void testB(){
B b = new B()
assert foo.foo(b)=='b'
}
@Test
void testBString(){
B b = new B()
assert foo.foo('foo',b)=='b'
}
@Test
void testBNull(){
B b = null
assert foo.foo(b)=='b'
}
@Test
void testBStringNull(){
B b = null
assert foo.foo('foo',b)=='b'
}
}
这是Groovy的多派遣机制(鲜为人知)如试图调用最合适的方法,并结合提供的静态类型(在您的情况下为A或B)不作为调度机制的一部分。当你声明A a = null时,你得到的不是A类型的空引用,而是对NullObject的引用。
最后,为了安全地处理可能的null参数重载的方法,调用者必须投入参数,如
A a = null
assert foo.foo(' foo',a as a)=='a'
关于可能会减少一些关于这个问题。
I'm a bit confused about groovys method overloading behavior: Given the classand tests below, I am pretty okay with testAStringNull
and testBStringNull
throwing ambiguous method call exceptions, but why is that not the case fortestANull
and testBNull
then?
And, much more importantly: why does testBNull(null)
call String foo(A arg)
? I guess the object doesn't know about the type of the variable it's bound to, but why is that call not ambiguous to groovy while the others are?
(I hope I explained well enough, my head hurts from generating this minimalexample.)
class Foo {
static class A {}
static class B {}
String foo(A arg) { return 'a' }
String foo(String s, A a) { return 'a' }
String foo(B arg) { return 'b' }
String foo(String s, B b) { return 'b' }
}
Tests:
import org.junit.Test
import Foo.A
import Foo.B
class FooTest {
Foo foo = new Foo()
@Test
void testA() {
A a = new A()
assert foo.foo(a) == 'a'
}
@Test
void testAString() {
A a = new A()
assert foo.foo('foo', a) == 'a'
}
@Test()
void testANull() {
A a = null
assert foo.foo(a) == 'a'
}
@Test
void testAStringNull() {
A a = null
assert foo.foo('foo', a) == 'a'
}
@Test
void testB() {
B b = new B()
assert foo.foo(b) == 'b'
}
@Test
void testBString() {
B b = new B()
assert foo.foo('foo', b) == 'b'
}
@Test
void testBNull() {
B b = null
assert foo.foo(b) == 'b'
}
@Test
void testBStringNull() {
B b = null
assert foo.foo('foo', b) == 'b'
}
}
It's a (somewhat little-known) oddity of Groovy's multi-dispatch mechanism, which as attempting to invoke the "most appropriate" method, in combination with the fact that the provided static type (in your case A or B) is not used as part of the dispatch mechanism. When you declare A a = null, what you get is not a null reference of type A, but a reference to NullObject.
Ultimately, to safely handle possibly null parameters to overloaded methods, the caller must cast the argument, as in
A a = null
assert foo.foo('foo', a as A) == 'a'
This discussion on "Groovy Isn't A Superset of Java" may shed some light on the issue.
这篇关于重载方法的意外行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!