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中,这是通过


但是,由于您处理的是
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中,调用的方法(如使用哪个方法签名)是在编译时确定的,因此它与编译时类型一起使用

解决此问题的典型模式是使用对象签名检查方法中的对象类型,并使用强制转换委托给方法

    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中,动态方法调度只针对调用方法的对象,而不是重载方法的参数类型

引用:

当调用方法时(§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);

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,这是违反直觉的理解这个谜题的关键是,哪种方法或构造函数最具体的测试不使用实际参数:调用中出现的参数。 它们被用在汽车上