【问题标题】:Method Overloading for null argument空参数的方法重载
【发布时间】:2013-10-27 15:40:22
【问题描述】:

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

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 方法?

【问题讨论】:

  • 只需将Integer 更改为int
  • @Mudassir:那到底能解决什么问题?
  • @Joachim Sauer:如果从 Integer 更改为 int,则 null 在 Java 中不会引用原始类型,因此编译器不会抛出错误。
  • @Joachim Sauer:它不会抛出 reference to doSomething is ambiguous 错误。

标签: java oop null overloading


【解决方案1】:

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

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

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

char[]Integer 版本都可用时,那么两个都比Object 更具体,但没有一个比另一个更具体,所以Java 无法决定打电话给哪个。在这种情况下,您必须通过将参数转换为适当的类型来明确提及您要调用哪一个。

请注意,在实践中,这个问题的发生比人们想象的要少得多。这样做的原因是,只有当您使用null 或使用相当非特定类型的变量(例如Object)显式调用方法时才会发生这种情况。

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

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

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

【讨论】:

  • 这是针对 Java 7 规定的。这是否也适用于以前的 Java 版本?我的意思是:如果你有几个方法签名,参数只在一个类型层次结构中,那么你是在保存端,将 null 作为实际值?如果你已经像这里的例子那样建立了一个“层次结构”,那么你不是吗?
  • 我很确定这些规则至少对于自 Java 1.1 以来的所有内容都是相同的(显然,除了添加泛型)。
  • 这是否意味着如果编译器在运行时使用 doSomething(null) 在 doSomething(String str) 和 doSomething(Object obj) 之间进行选择,则会调用 doSomething(String str)。
【解决方案2】:

当使用null 参数调用时,这三个方法中的每一对本身都是不明确的。因为每个参数类型都是引用类型。

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

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

如果您确实打算使用null 参数调用这些方法,我建议您消除这种歧义。这样的设计会在未来引发错误。

【讨论】:

  • 只有Integer-char[]对是不明确的,因为在其他两种情况下,Java编译器可以选择最具体的选择,就像@JoachimSauer描述的那样。
  • @kajacx:OPs 最初的问题是关于以null 作为参数调用这些方法。在这个前提下,所有三对都是模棱两可的。对于一般情况,我同意只有 Integer - char[] 对是模棱两可的。
  • doSomething(null) for public static void doSomething(String str) { System.out.println("String called"); } 怎么样?这将返回调用的字符串。
  • 是否可以使用“可为空”或“不可为空”之类的注释并设置声明,以便仅使用您想要获取空值的一种方法,以便显式“空”(尚未隐式空类型)参数总是明确地选择一个特定的重载??
【解决方案3】:

null 是三种类型中任何一种的有效值;所以编译器无法决定使用哪个函数。请改用doSomething((Object)null)doSomething((Integer)null) 之类的东西。

【讨论】:

  • 我删除了带有 Integer 参数的方法,它正在调用函数并将输出返回为 "Array Called",那么 Array 和 Object 之间的约定是什么?
  • Java 数组也是对象。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

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

    由于这是一个编译时事件,只有在有意将 null 传递给此方法时才会发生这种情况。如果这是有意完成的,那么最好在没有参数的情况下再次重载此方法或完全创建另一个方法。

    【讨论】:

      【解决方案6】:

      由于 doSomething(char[] obj) 和 doSomething(Integer obj) 存在歧义。

      char[] 和 Integer 对于 null 这两者都具有相同的优越性,这就是为什么它们是模棱两可的。

      【讨论】:

        【解决方案7】:
        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 有歧义

        【讨论】:

        • 你知道为什么这个方法会调用public static void printVal(Object i){ System.out.println("obj called "+i); }
        猜你喜欢
        • 2017-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-19
        • 2015-07-19
        • 1970-01-01
        相关资源
        最近更新 更多