我正在尝试这段代码:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
Run Code Online (Sandbox Code Playgroud)
这打印foo(Object o)三次.我希望方法选择考虑到真实的(不是声明的)参数类型.我错过了什么吗?有没有办法修改这个代码,以便打印foo(12),foo("foobar")和foo(Object o)?
Mic*_*rdt 91
我希望方法选择考虑到真实的(不是声明的)参数类型.我错过了什么吗?
是.你的期望是错误的.在Java中,动态方法分派仅针对调用方法的对象发生,而不是针对重载方法的参数类型.
引用Java语言规范:
调用方法时(第15.12节), 在编译时使用实际参数的数量(以及任何显式类型参数)和参数的编译时类型来确定将被调用的方法的签名( §15.12.2).如果要调用的方法是实例方法,则将在运行时使用动态方法查找(第15.12.4节)确定要调用的实际方法.
den*_*nov 83
如前所述,重载分辨率是在编译时执行的.
Java Puzzlers有一个很好的例子:
谜题46:令人困惑的构造函数的案例
这个谜题为您提供了两个令人困惑的构造函数.main方法调用构造函数,但是哪一个?程序的输出取决于答案.该程序打印什么,甚至是合法的?
public class Confusing {
private Confusing(Object o) {
System.out.println("Object");
}
private Confusing(double[] dArray) {
System.out.println("double array");
}
public static void main(String[] args) {
new Confusing(null);
}
}
Run Code Online (Sandbox Code Playgroud)
解决方案46:令人困惑的构造函数的情况
... Java的重载解析过程分两个阶段进行.第一阶段选择可访问和适用的所有方法或构造函数.第二阶段选择在第一阶段中选择的最具体的方法或构造函数.如果一个方法或构造函数可以接受传递给另一个的任何参数[JLS 15.12.2.5],那么它的特定性不如另一个.
在我们的程序中,两个构造函数都是可访问和适用的.构造函数 Confusing(Object)接受传递给Confusing(double [])的任何参数,因此 Confusing(Object)不太具体.(每个double数组都是一个Object,但不是每个Object都是一个double数组.)因此,最具体的构造函数是Confusing(double []),它解释了程序的输出.
如果传递double []类型的值,则此行为很有意义; 如果你传递null,这是违反直觉的.理解这个难题的关键是对哪个方法或构造函数最具体的测试不使用实际参数:调用中出现的参数.它们仅用于确定适用的过载.一旦编译器确定哪些重载适用且可访问,它就只使用形式参数选择最具体的重载:声明中出现的参数.
要使用null参数调用Confusing(Object)构造函数,请编写新的Confusing((Object)null).这确保了只有Confusing(Object)适用.更一般地,强制编译器选择特定的重载,将实际参数转换为形式参数的声明类型.
Yis*_*hai 11
在Java中,调用方法(如使用哪个方法签名)是在编译时确定的,因此它与编译时类型一致.
解决此问题的典型模式是使用Object签名检查方法中的对象类型,并使用强制转换委托给方法.
public void foo(Object o) {
if (o instanceof String) foo((String) o);
if (o instanceof Integer) foo((Integer) o);
logger.debug("foo(Object o)");
}
Run Code Online (Sandbox Code Playgroud)
如果你有很多类型并且这是无法管理的,那么方法重载可能不是正确的方法,而是公共方法应该只使用Object并实现某种策略模式来委托每个对象类型的适当处理.
| 归档时间: |
|
| 查看次数: |
48716 次 |
| 最近记录: |