重载方法的意外行为 [英] Unexpected behavior with overloaded methods

查看:95
本文介绍了重载方法的意外行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对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'

关于Groovy不是Java的超集可能会减少一些关于这个问题。


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'
    }

}

解决方案

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.

这篇关于重载方法的意外行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆