【问题标题】:Method overload selection with null方法重载选择与 null
【发布时间】:2013-05-12 03:38:53
【问题描述】:

鉴于此代码:

class Overloading
extends Object
{

static public void target(Object val, String chk) { System.out.println("Object["+val+"] :: Should be "+chk); }
static public void target(String val, String chk) { System.out.println("String["+val+"] :: Should be "+chk); }

static public void main(String[] args) {
    Object                              obj=null;

    target(null        ,"Object");
    target((Object)null,"Object");
    target(obj         ,"Object");
    }
}

输出(意外)如下:

String[null] :: Should be Object
Object[null] :: Should be Object
Object[null] :: Should be Object

问题在于第一行,我希望它与其他两行相同。此外,我发誓直到最近编译器才会对普通的null 调用发出模棱两可的调用警告。但是,使用 Java 5 和 6 进行编译和测试会产生相同的结果。

这对我来说是一个重大问题,因为我有很多代码使用这种模式,即使用不同类型的重载“默认”参数来选择返回类型并推断所需的转换/解析。谁能解释这里发生了什么?

【问题讨论】:

标签: java overloading


【解决方案1】:

Java 一直以同样的方式工作:总是选择“最具体”的适用重载。由于StringObject 的子类,因此它“更具体”,因此选择了String 重载。如果重载是针对StringInteger,并且您尝试传递null,那么您确实会收到编译时歧义错误,因为它们都处于同一继承层次结构的同一级别。

【讨论】:

  • 是的,我相信你是对的;在其他代码中,我还对数字或原始数组进行了覆盖,这两者都足以触发歧义警告。我已经通过添加 Number 重载与 String 冲突解决了我当前的问题......但现在我对这种一般模式不太满意(尽管现在有太多代码取决于它,不值得全部更改)。
  • @SoftwareMonkey,我面临与您类似的问题。我通过在函数中添加一行来解决:static public void target(String val, String chk) { if (val == null) { target((Object) val, chk); } System.out.println("String["+val+"] :: Should be "+chk); }。你觉得效果好吗?
  • @midnite:不,那不行。在我的例子中,我使用参数类型来选择调用的函数,这反过来又决定了 return 类型。但是null 的情况很特殊,我需要歧义警告来提醒程序员提供一个“类型化”的空值(即,一个初始化为空的特定类型值,而不是关键字null)来选择预期的返回类型.
  • 首先,我很抱歉我上面的代码有问题。应该是if (val == null) { target((Object) val, chk); return; }。并感谢@SoftwareMonkey。这在设计上真的很值得思考。我的情况有点不同。我将相同的函数名称用于不同目的的函数。一个x(String, Object),我想匹配除字符串之外的所有内容。另一个x(String, String) 正在做不同的事情。我知道同时使用x 可能不好。但它使用户代码更短更简单(并且看起来更聪明)。有什么建议吗?
  • 如何解决具有原始数据类型的函数的冲突,例如。 func(int, long) 和 func (long,int) 并被称为 func(4,4)。
【解决方案2】:

请记住,文字 null 是“特殊空类型”类型,而不是 Object 类型

一个常见的混淆是文字 nullObject 类型,因此导致人们相信最接近匹配的签名是 target(Object val, String chk)

文字null 实际上是“[特殊空类型]”类型(Java Language Spec (JLS) 4)。如果可以定义这样的方法,最接近的匹配将是target([special null type] val, String chk)

但是,由于没有这样的方法(您无法创建一个),编译器通过子类型(JLS 15.12.2.2)查找最接近的匹配。 [特殊空类型]的直接超类型都是引用类型(JLS 4.10.2)(例如String),Object是String的超类型。


也许更直观的方式是通过 JLS 对“最具体方法”的直观定义 (JLS 15.12.2.5):

“非正式的直觉是一种方法比 如果可以传递第一个方法处理的任何调用,则另一个 在另一个没有编译时类型错误的情况下。”

在调用 target(null ,"Object") 匹配的两个方法中,任何对

的调用
void target(String val, String chk)

可以处理

void target(Object val, String chk)

如此直观地void target(String val, String chk) 是可以在没有类型错误的情况下调用的“最具体的”。

请参阅JLS 15.12.2.5,了解如何正式定义“最具体”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-18
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多