空参数的方法重载


133

我添加了三个带有参数的方法:

public static  void doSomething(Object obj) {
    System.out.println("Object called");
}

public static  void doSomething(char[] obj) {
    System.out.println("Array called");
}

public static  void doSomething(Integer obj) {
    System.out.println("Integer called");
}

当我打电话时doSomething(null),编译器将错误作为模棱两可的方法抛出。那么问题是因为Integerchar[]方法还是IntegerObject方法?


3
只需将更Integer改为即可int
Mudassir

2
@Mudassir:那到底能解决什么?
Joachim Sauer

2
@Joachim Sauer:如果从Integer更改为int,则在Java中null不会引用基本类型,因此编译器不会引发错误。
Phani

@Joachim Sauer:不会抛出reference to doSomething is ambiguous错误。
Mudassir

Answers:


211

Java将始终尝试使用可用方法的最特定适用版本(请参见JLS§15.12.2)。

Objectchar[]并且Integer都可以null作为有效值。因此,所有3个版本均适用,因此Java必须找到最具体的版本。

由于Object是的超类型char[],因此数组版本比Object-version 更具体。因此,如果仅存在这两种方法,char[]则将选择版本。

当两个char[]Integer版本可用,则两者都是比更具体的Object,但没有一个比另一个更具体,所以Java不能决定哪一个调用。在这种情况下,您必须通过将参数强制转换为适当的类型来明确提及要调用的那个。

请注意,实际上,此问题的发生比人们想象的要少得多。这样做的原因是,仅当您显式地调用带有null非特定类型的变量(例如Object)的方法时,才会发生这种情况。

相反,以下调用将是完全明确的:

char[] x = null;
doSomething(x);

尽管您仍在传递值null,但是Java确切知道要调用哪个方法,因为它将考虑变量的类型。


1
Java 7对此进行了说明。这是否也适用于以前的Java版本?我的意思是:如果您有几个仅沿类型层次结构带有参数的方法签名,那么您是在保存方面以null作为实际值吗?如果您像这里的示例那样建立了“层次结构”,那么您不是吗?
Christian Gosch,2015年

2
我很确定这些规则至少对于Java 1.1以来的所有东西都是相同的(显然,除了泛型外)。
Joachim Sauer

这是否意味着如果编译器在运行时使用doSomething(null)在doSomething(String str)和doSomething(Object obj)之间进行选择,则将调用doSomething(String str)。
Sameer

42

当使用null参数调用时,这三种方法中的每对本身都是模棱两可的。因为每种参数类型都是引用类型。

以下是使用null调用您的一种特定方法的三种方法。

doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);

如果您实际计划使用null参数调用这些方法,我可以建议消除这种歧义。这样的设计将来会引起错误。


1
唯一Integer- char[]对是模棱两可的,因为在其他两种情况下,Java编译器可以选择最具体的选择,如@JoachimSauer所述。
kajacx

1
@kajacx:OP最初的问题是关于使用nullas作为参数调用这些方法。在此前提下,所有三对都是模棱两可的。对于一般情况,我同意只有Integer - char[]一对是模棱两可的。
jmg 2015年

怎么回事doSomething(null)public static void doSomething(String str) { System.out.println("String called"); } 这将返回称为的字符串。
Sameer

是否可以使用“ nullable”或“ not nullable”之类的注释并设置声明,以便仅使用一个您想要获取null的方法,以便始终明确选择“ null”(但隐式null类型)参数具体的过载
peterk

4

null是这三种类型中任何一种的有效值;因此编译器无法决定使用哪个函数。使用类似doSomething((Object)null)doSomething((Integer)null)代替的东西。


我删除了带有Integer参数的方法,它正在调用函数并以“ Array Called”返回输出,那么Array和Object之间的协定是什么?
Phani

2
Java数组也是对象。
Zds 2011年

2

Java中的每个类都扩展了Object类。甚至Integer类也扩展了Object。因此,对象和整数都被视为对象实例。因此,当您将null用作参数时,编译器会混淆调用哪个对象方法,即使用参数Object或parameter Integer,因为它们都是对象并且其引用可以为null。但是Java中的原语不会扩展Object。


1

我已经尝试过了,当正好有一对重载方法并且其中一个具有参数类型Object时,编译器将始终选择具有更特定类型的方法。但是,当有多个特定类型时,编译器将抛出一个模棱两可的方法错误。

由于这是一个编译时事件,因此只有在有意将null传递给此方法时,才会发生这种情况。如果有意这样做,则最好再次重载此方法而没有任何参数,或者完全创建另一个方法。


0

由于doSomething(char [] obj)和doSomething(Integer obj)导致模棱两可。

char []和Integer都比null优越,这就是为什么它们不明确的原因。


0
class Sample{
  public static void main (String[] args) {
       Sample s = new Sample();
       s.printVal(null);

    } 
    public static void printVal(Object i){
        System.out.println("obj called "+i);
    }

    public static void printVal(Integer i){
        System.out.println("Int called "+i);
    }
}

输出为Int,称为null,因此模糊度与char []和Integer

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.