I'm a bit confused about groovys method overloading behavior: Given the class
and tests below, I am pretty okay with testAStringNull
and testBStringNull
throwing ambiguous method call exceptions, but why is that not the case for
testANull
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 minimal example.)
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'
}
}
Overloaded methods are differentiated based on the number and type of parameter passed as arguments to the methods. If we try to define more than one method with the same name and the same number of arguments then the compiler will throw an error.
Method overloading increases the readability of the program. Overloaded methods give programmers the flexibility to call a similar method for different types of data. Overloading is also used on constructors to create new objects given different amounts of data.
In Java, two or more methods may have the same name if they differ in parameters (different number of parameters, different types of parameters, or both). These methods are called overloaded methods and this feature is called method overloading.
Overloaded methods are differentiated by the number and the type of the arguments passed into the method. In the code sample, draw(String s) and draw(int i) are distinct and unique methods because they require different argument types.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With