下面是具有3个重载构造函数的java类:
public class Test {
public Test(Object i){
System.out.println("Object invoked");
}
public Test(String i){
System.out.println("String invoked");
}
public Test(int k){
System.out.println("Integer invoked");
}
public static void main(String[] args) throws Exception {
Test t = new Test(null);
}
}
如果在创建新的类实例时传递了null值,那么将调用哪个构造函数?是什么原因?
答案 0 :(得分:11)
Java始终选择最适合您传递的参数的特定方法(或构造函数)。在这种情况下,String
构造函数 - String
是Object
的子类。
想想如果你有
会发生什么new Test("some string")
这两个 Object
和String
构造函数都适用于此处。毕竟,论证既是Object
又是String
。 然而,显然会调用String
构造函数,因为它比Object
构造函数更具体,并且在给定参数的情况下仍然适用。
null
也不例外;这两个构造函数仍然适用,String
构造函数仍然在Object
构造函数上被选中,原因相同。
现在,如果存在两个同样“特定”的构造函数(例如,如果你有一个Integer
构造函数),那么当你调用Test(null)
时会出现编译错误。
JLS §15.12.2中详细介绍了这一点:
第二步搜索上一步中为成员方法确定的类型。此步骤使用方法的名称和参数表达式的类型来定位可访问和适用的方法,即可以在给定参数上正确调用的声明。
可能有多个这样的方法,在这种情况下,选择最具体的。最具体方法的描述符(签名加返回类型)是在运行时用于执行方法调度的方法。
JLS §15.12.2.5概述了确定哪种方法最具体的明确流程。
答案 1 :(得分:0)
答案是:Test(String)
被调用。
为什么?
在确定将调用哪一组重载方法时,Java编译器将尝试匹配最具体的类型。并且它将首先尝试匹配之前使用自动装箱的签名。 (@arshajii提供了关于Java语言规范的完美参考)
这里,Object
是类型系统中最抽象的类。来自String
的{{1}}子类,因此更具体/具体。
这背后的逻辑是,如果您使用更具特定类型的参数重载方法,则可能希望对该对象执行更多操作(当您进行子类化时,通常会添加方法)。如果方法签名确定以另一种方式工作(即更抽象类型的签名获胜;此处为Object
),则不会调用任何更具体的签名。