使用null的方法重载选择

时间:2011-08-26 00:50:56

标签: java overloading

鉴于此代码:

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进行编译和测试会产生相同的结果。

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

2 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:3)

请注意,文字null的类型为“特殊空类型”,而不是类型Object

常见的混淆是文字null的类型为Object,因此会让人们相信最匹配的签名是target(Object val, String chk)

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

但是,由于没有这样的方法(您无法创建),编译器会通过子类型(JLS 15.12.2.2)查找最接近的匹配。 [特殊null类型]的直接超类型都是引用类型(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了解“最具体”的定义方式。