当参数是文字空值时,如何选择重载方法?
Posted
技术标签:
【中文标题】当参数是文字空值时,如何选择重载方法?【英文标题】:How is an overloaded method chosen when a parameter is the literal null value? 【发布时间】:2012-10-13 12:54:57 【问题描述】:我在一次测验中遇到了这个问题,
public class MoneyCalc
public void method(Object o)
System.out.println("Object Verion");
public void method(String s)
System.out.println("String Version");
public static void main(String args[])
MoneyCalc question = new MoneyCalc();
question.method(null);
这个程序的输出是“字符串版本”。但我无法理解为什么将 null 传递给重载方法会选择字符串版本。 null 是一个不指向任何东西的字符串变量吗?
但是当代码改为,
public class MoneyCalc
public void method(StringBuffer sb)
System.out.println("StringBuffer Verion");
public void method(String s)
System.out.println("String Version");
public static void main(String args[])
MoneyCalc question = new MoneyCalc();
question.method(null);
它给出了一个编译错误,说“方法 method(StringBuffer) 对于 MoneyCalc 类型不明确”
【问题讨论】:
您可以将字符串分配给空值,使其有效,并且 java 和大多数编程语言的顺序适合最接近的类型,然后适合对象。 ***.com/a/1572499/231290 显然这已被只阅读标题的人关闭为重复。这里的实际问题是为什么选择特定的重载,而不是“什么是空的”。 【参考方案1】:null 是一个指向空的字符串变量吗?
空引用可以转换为任何类类型的表达式。所以在String
的情况下,这很好:
String x = null;
这里选择String
重载是因为Java 编译器根据section 15.12.2.5 of the JLS 选择最具体的 重载。特别是:
非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个方法而不会出现编译时类型错误,那么一个方法比另一个方法更具体。
在您的第二种情况下,这两种方法仍然适用,但 String
和 StringBuffer
都没有比另一种更具体,因此没有一种方法比另一种更具体,因此编译器错误。
【讨论】:
String 重载比 Object 重载更具体吗? 因为Object
可以采用任何类型并将其包装在Object
中,而String
只能采用String
。在这种情况下,String
比 Object
类型更具体。
@zakSyed 如果有人问你什么是更专业的“字符串”或“对象”,你会说什么?显然是“字符串”,对吧?如果有人问你:什么是更专业的“String”或“StringBuffer”?没有答案,它们都是正交专业,你如何选择它们?然后你必须明确你想要哪一个(即通过转换你的空引用question.method((String)null)
)
@JonSkeet:这是有道理的。所以基本上它会根据最具体的规则寻找一个方法,如果它不能决定哪个更具体,那么它会抛出一个编译时错误。
@JonH "null" 是引用类型,如果其中一个方法接收原始类型作为参数(即 int),编译器甚至不会在选择正确的方法来调用null 类型的引用。如果“Int”是指 java.lang.Integer 或原始类型 int,则会令人困惑。【参考方案2】:
此外,JLS 3.10.7 还声明“null”是“null 类型”的文字值。因此存在一种称为“null”的类型。
后来,JLS 4.1 声明存在一个无法声明变量的 null 类型,但您只能通过 null 文字使用它。后来它说:
空引用总是可以进行加宽引用转换 到任何引用类型。
为什么编译器选择将其扩展为 String 可能会在 Jon's answer 中进行解释。
【讨论】:
我很确定该类型是 Void。 @xavierm02 Java 语言规范中没有提到这一点。您能否引用您的参考资料,以便我们都可以验证您的声明? 我从来没有读过那个东西。但今年夏天我确实做了一些 Java,你可以用一个采用 Void 对象的方法重载采用 Object 的方法。 它更像是一个类而不是一个类型。 @xavierm02 当然可以。您可以使用您想要的任何其他类型重载 Java 中的方法。尽管如此,这与问题或我的回答无关。【参考方案3】:您可以将string
分配给null
值,使其有效并且java 和大多数编程语言的顺序适合最接近的类型,然后适合对象。
【讨论】:
【参考方案4】:要回答标题中的问题:null
既不是 String
也不是 Object
,但可以将两者的引用分配给 null
。
我真的很惊讶这段代码甚至可以编译。我之前尝试过类似的方法,但我得到一个编译器错误,说调用不明确。
但是,在这种情况下,编译器似乎选择了食物链上最低的方法。它假设您想要该方法的最通用版本以帮助您。
我将不得不看看我是否可以挖掘出在这个(看似)完全相同的场景中出现编译器错误的示例,不过......]
编辑:我明白了。在我制作的版本中,我有两个接受String
和Integer
的重载方法。在这种情况下,没有“最具体”的参数(如 Object
和 String
),因此无法在它们之间进行选择,这与您的代码不同。
非常酷的问题!
【讨论】:
null 两者都不是,但它可以分配给两者,这就是区别,它会编译为什么不它 - 它是绝对有效的代码。【参考方案5】:因为 String 类型比 Object 类型更具体。假设您再添加一个采用 Integer 类型的方法。
public void method(Integer i)
System.out.println("Integer Version");
然后你会得到一个编译器错误,说调用不明确。就像现在我们两个具有相同优先级的相同特定方法。
【讨论】:
【参考方案6】:Java 编译器将大多数派生类类型赋予 null。
这是理解它的示例:
class A
public void methodA()
System.out.println("Hello methodA");
class B extends A
public void methodB()
System.out.println("Hello methodB");
class C
public void methodC()
System.out.println("Hello methodC");
public class MyTest
public static void fun(B Obj)
System.out.println("B Class.");
public static void fun(A Obj)
System.out.println("A Class.");
public static void main(String[] args)
fun(null);
输出: B 类。
另一方面:
public class MyTest
public static void fun(C Obj)
System.out.println("B Class.");
public static void fun(A Obj)
System.out.println("A Class.");
public static void main(String[] args)
fun(null);
结果:方法 fun(C) 对于 MyTest 类型不明确
希望这将有助于更好地理解这个案例。
【讨论】:
【参考方案7】:来源: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5 概念:最具体的方法 说明:如果多个成员方法既可访问又适用于方法调用,则需要选择一个为运行时方法分派提供描述符。 Java 编程语言使用选择最具体方法的规则。尝试将 null 强制转换为特定类型,您希望的方法将被自动调用。
【讨论】:
在第一个例子中,String扩展了Object,所以“最具体”的是采用String的方法,但在第二个例子中,String和StringBuffer 都扩展了Object,所以它们同样具体,因此编译器无法做出选择【参考方案8】:我都不会说。 NULL 是一个状态而不是一个值。查看link 了解更多信息(这篇文章适用于 SQL,但我认为它对您的问题也有帮助)。
【讨论】:
null
绝对是一个值,如 JLS 中所定义。以上是关于当参数是文字空值时,如何选择重载方法?的主要内容,如果未能解决你的问题,请参考以下文章
仅当非空值时,如何在输入和过滤数据中具有默认的 NULL 值?
当用户使用 ajax 在 laravel 中选择任何下拉值时,如何立即显示数据库详细信息?