重载解析,调用哪个方法
Overload resolution, which method is called
假设我有一个 ComponentBase
class,他是 ObjectContextDecorator
的 child 和 ObjectContext
的 grandchild。
public class ComponentBase extends ObjectContextDecorator {
}
public class ObjectContextDecorator extends ObjectContext {
public void set(String objectTypePath, String characteristicName, Object value) {
//...
}
}
public class ObjectContext {
public void set(String characteristicName, Object value, boolean forced) {
//...
}
}
ObjectContextDecorator
和ObjectContext
上的set
方法非常相似。考虑这个示例代码:
ComponentBase base = new ComponentBase();
base.set(""OTM4E_EFFLEVEL"", ""IE1 / STD"", true);
两种方法的签名都适合被正确调用的方法。我无法更改方法的签名,因为它不是我的代码。
编译器如何知道我打算调用哪个方法?
我知道在 IDE 上你可以指出你实际打算调用哪个方法,但在这种情况下,我使用 class 加载器加载 class 其中有一个包含示例代码的方法。
JLS §15.2 方法调用表达式中均有解释。它会告诉您如何选择正确的调用方法。请注意,这并不总是成功。
在您的特定情况下,这两个方法是彼此的重载,因此适用第 15.2.2 节“编译时步骤 2:确定方法签名”——调用哪个重载是在编译时确定的。此步骤进一步分为 3 个阶段。
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.
在第一阶段,编译器尝试在不允许装箱转换的情况下找到适用的方法。在您的情况下,要调用采用 Object
的重载,需要进行装箱转换以将 boolean
true
转换为类型 Object
,这样重载就不会第一阶段被选中
If no method applicable by strict invocation is found, the search for applicable methods continues with phase 2 (§15.12.2.3).
Otherwise, the most specific method (§15.12.2.5) is chosen among the methods that are applicable by strict invocation.
好吧,我们已经找到了一个方法,所以我们将只选择那个方法。没有歧义。
How does the compiler know which method I intended to call?
它检查参数并根据描述的规则确定哪个更具体 JLS §15.2
在你的例子中,调用:
base.set("OTM4E_EFFLEVEL", "IE1 / STD", true)
参数是 String
、String
、boolean
匹配第一个 class(为简洁起见更改了参数名称)
public class ObjectContext {
public void set(String s, Object o, boolean b){
//...
}
}
第二个 class 未被调用 因为第三个参数是 Object
:
public class ObjectContextDecorator extends ObjectContext {
public void set(String s, String ss, Object thisOneRightHere) {
//...
}
}
虽然布尔值 true
可以匹配如果它是自动装箱的,但第一个更具体。此处应用的规则是:
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion
但是,例如,如果您在签名中使用对象包装器 Boolean
:
public class ObjectContext {
public void set(String s, Object o, Boolean b){ //<-- third param changed from boolean to Boolean
//...
}
}
然后它们都会匹配,编译器会通过以下消息通知您:
> A.java:25: error: reference to set is ambiguous
> base.set("OTM4E_EFFLEVEL", "IE1 / STD", true);
> ^ both method set(String,Object,Boolean) in ObjectContext and method set(String,String,Object) in ObjectContextDecorator match
但是你的例子不是这种情况。
假设我有一个 ComponentBase
class,他是 ObjectContextDecorator
的 child 和 ObjectContext
的 grandchild。
public class ComponentBase extends ObjectContextDecorator {
}
public class ObjectContextDecorator extends ObjectContext {
public void set(String objectTypePath, String characteristicName, Object value) {
//...
}
}
public class ObjectContext {
public void set(String characteristicName, Object value, boolean forced) {
//...
}
}
ObjectContextDecorator
和ObjectContext
上的set
方法非常相似。考虑这个示例代码:
ComponentBase base = new ComponentBase();
base.set(""OTM4E_EFFLEVEL"", ""IE1 / STD"", true);
两种方法的签名都适合被正确调用的方法。我无法更改方法的签名,因为它不是我的代码。
编译器如何知道我打算调用哪个方法?
我知道在 IDE 上你可以指出你实际打算调用哪个方法,但在这种情况下,我使用 class 加载器加载 class 其中有一个包含示例代码的方法。
JLS §15.2 方法调用表达式中均有解释。它会告诉您如何选择正确的调用方法。请注意,这并不总是成功。
在您的特定情况下,这两个方法是彼此的重载,因此适用第 15.2.2 节“编译时步骤 2:确定方法签名”——调用哪个重载是在编译时确定的。此步骤进一步分为 3 个阶段。
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.
在第一阶段,编译器尝试在不允许装箱转换的情况下找到适用的方法。在您的情况下,要调用采用 Object
的重载,需要进行装箱转换以将 boolean
true
转换为类型 Object
,这样重载就不会第一阶段被选中
If no method applicable by strict invocation is found, the search for applicable methods continues with phase 2 (§15.12.2.3).
Otherwise, the most specific method (§15.12.2.5) is chosen among the methods that are applicable by strict invocation.
好吧,我们已经找到了一个方法,所以我们将只选择那个方法。没有歧义。
How does the compiler know which method I intended to call?
它检查参数并根据描述的规则确定哪个更具体 JLS §15.2
在你的例子中,调用:
base.set("OTM4E_EFFLEVEL", "IE1 / STD", true)
参数是 String
、String
、boolean
匹配第一个 class(为简洁起见更改了参数名称)
public class ObjectContext {
public void set(String s, Object o, boolean b){
//...
}
}
第二个 class 未被调用 因为第三个参数是 Object
:
public class ObjectContextDecorator extends ObjectContext {
public void set(String s, String ss, Object thisOneRightHere) {
//...
}
}
虽然布尔值 true
可以匹配如果它是自动装箱的,但第一个更具体。此处应用的规则是:
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion
但是,例如,如果您在签名中使用对象包装器 Boolean
:
public class ObjectContext {
public void set(String s, Object o, Boolean b){ //<-- third param changed from boolean to Boolean
//...
}
}
然后它们都会匹配,编译器会通过以下消息通知您:
> A.java:25: error: reference to set is ambiguous
> base.set("OTM4E_EFFLEVEL", "IE1 / STD", true);
> ^ both method set(String,Object,Boolean) in ObjectContext and method set(String,String,Object) in ObjectContextDecorator match
但是你的例子不是这种情况。