在具有重载构造函数的类中传递null时首先调用哪个构造函数?
下面是具有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值,那么将调用哪个构造函数? 是什么原因 ?
Java总是选择适用于您传递的参数的最具体的方法(或构造函数)。 在这种情况下,这是String
构造函数 – String
是Object
的子类。
想想如果你有什么会发生什么
new Test("some string")
Object
和String
构造函数都适用于此处。 毕竟,参数既是Object
又是String
。 但是 ,很明显将调用String
构造函数,因为它比Object
构造函数更具体,并且在给定参数的情况下仍然适用。
null
也不例外; 这两个构造函数仍然适用,并且由于同样的原因,仍然在Object
构造函数上选择了String
构造函数。
现在,如果存在两个同样“特定”的构造函数(例如,如果您有一个Integer
构造函数),则在调用Test(null)
时会出现编译错误。
这在JLS§15.12.2中有更详细的概述:
第二步搜索上一步中为成员方法确定的类型。 此步骤使用方法的名称和参数表达式的类型来定位可访问和适用的方法,即可以在给定参数上正确调用的声明。
可能存在多于一种这样的方法,在这种情况下,选择最具体的方法。 最具体方法的描述符(签名加返回类型)是在运行时用于执行方法分派的方法。
JLS§15.12.2.5中概述了确定哪种方法最具体的明确过程。
答案是:调用Test(String)
。
为什么?
在确定将调用哪一组重载方法时,Java编译器将尝试匹配最具体的类型。 在使用自动装箱之前 ,它将首先尝试匹配签名。 (@arshajii提供了关于Java语言规范的完美参考)
这里, Object
是类型系统中最抽象的类。 来自Object
String
子类因此更具体/具体。
这背后的逻辑是,如果您使用更具体类型的参数重载方法,您可能希望对该对象执行更多操作(当您进行子类化时,通常会添加方法)。 如果方法签名确定以另一种方式工作(即更抽象类型的签名获胜;这里是Test(Object)
),则不会调用任何更具体的签名。