Java 基于参数';这是真正的类型
我正在试验以下代码:Java 基于参数';这是真正的类型,java,oop,Java,Oop,我正在试验以下代码: 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
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);
这将打印
foo(对象o)
三次。我希望方法选择考虑真实(而不是声明的)参数类型。我错过什么了吗?是否有方法修改此代码,使其打印foo(12)
,foo(“foobar”)
和foo(对象o)
?调用基于参数类型对方法进行调用的能力。在Java中,这是通过
但是,由于您处理的是
Integer
s和String
s,因此无法轻松合并此模式(您只是无法修改这些类)。因此,对象运行时上的一个巨大的开关将是您选择的武器。在Java中,要调用的方法(如要使用的方法签名)是在编译时确定的,因此它与编译时类型有关
解决此问题的典型模式是使用对象签名检查方法中的对象类型,并使用强制转换委托给方法
public void foo(Object o) {
if (o instanceof String) foo((String) o);
if (o instanceof Integer) foo((Integer) o);
logger.debug("foo(Object o)");
}
如果您有许多类型,并且这是不可管理的,那么方法重载可能不是正确的方法,相反,公共方法应该只接受对象并实现某种策略模式,以委派每个对象类型的适当处理
我希望选择的方法
考虑到真实(而非真实)
声明的)参数类型。我失踪了吗
什么
对。你的期望是错误的。在Java中,动态方法调度只针对调用方法的对象,而不是重载方法的参数类型
引用:
当调用方法时(§15.12)
实际参数数(以及任何
显式类型参数)和
参数的编译时类型
在编译时用于
确定方法的签名
将被调用(§15.12.2)。如果
要调用的方法是
实例方法,用于
将在运行时确定是否调用
时间,使用动态方法查找
(§15.12.4)
Java在试图确定调用哪个方法时会查看引用类型。如果要强制执行代码,请选择“right”方法,您可以将字段声明为特定类型的实例:
Integeri = new Integer(12);
String s = "foobar";
Object o = new Object();
您还可以将参数强制转换为参数的类型:
callee.foo(i);
callee.foo((String)s);
callee.foo(((Integer)o);
如前所述,重载解析是在编译时执行的
有一个很好的例子:
谜题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);
}
}
解决方案46:构造函数混乱的情况
。。。
Java的重载解析过程分为两个阶段。第一阶段选择所有可访问和适用的方法或构造函数。第二阶段选择第一阶段中选择的最具体的方法或构造函数。如果一个方法或构造函数可以接受传递给另一个方法或构造函数的任何参数,则该方法或构造函数不如另一个方法或构造函数具体[JLS 15.12.2.5]
在我们的程序中,两个构造函数都是可访问和适用的。构造器
fuzzing(Object)接受传递给fuzzing(double[])的任何参数,因此
混淆(对象)不太具体。(每个双数组都是一个对象,但不是每个对象都是双数组。)因此,最具体的构造函数(double[])令人困惑,这解释了程序的输出
如果传递double[]类型的值,则此行为有意义;如果传递null,这是违反直觉的理解这个谜题的关键是,哪种方法或构造函数最具体的测试不使用实际参数:调用中出现的参数。
它们仅用于确定哪些过载适用。一旦编译器确定哪些重载是适用的和可访问的,它就会选择最具体的重载,只使用形式参数:声明中出现的参数
要使用空参数调用混乱的(对象)构造函数,请编写新的
混淆((对象)null)。这可确保仅适用于易混淆的(对象)。更多
通常,要强制编译器选择特定的重载,请将实际参数强制转换为声明的形式参数类型。我在调用名为“Parameter”的类的正确构造函数时遇到了类似问题,该类可以采用多种基本Java类型,如String、Integer、Boolean、Long等。给定一个对象数组,我想通过为输入数组中的每个对象调用最具体的构造函数,将它们转换为参数对象数组。我还想定义将引发IllegalArgumentException的构造函数参数(对象o)。当然,我发现数组中的每个对象都调用了这个方法
我使用的解决方案是通过反射查找构造函数
public Parameter[] convertObjectsToParameters(Object[] objArray) {
Parameter[] paramArray = new Parameter[objArray.length];
int i = 0;
for (Object obj : objArray) {
try {
Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass());
paramArray[i++] = cons.newInstance(obj);
} catch (Exception e) {
throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e);
}
}
return paramArray;
}
public参数[]convertObjectStopParameters(对象[]objArray){
参数[]paramArray=新参数[objArray.length];
int i=0;
用于(对象obj:objArray){
试一试{
构造函数cons=Parameter.class.getConstructor(obj.getClass());
paramArray[i++]=cons.newInstance(obj);
}捕获(例外e){
抛出新的IllegalArgumentException(“此方法无法处理类型:”+obj.getClass(),e)的对象);
}
}
返回参数数组;
}
不需要丑陋的instanceof、switch语句或访问者模式!:) 如果在方法调用中指定的参数数量和类型与重载方法的方法签名之间存在精确匹配,则该方法将被调用。您使用的是对象引用,所以JavaDeci