2

我最近遇到了以下场景:

我有一个超类 A 和一个从中派生的 B 类。一个函数,比如 oracle,返回任一类型的对象。我想根据类型做不同的事情,但我不能为 A 和 B 引入新的成员函数。

一种解决方案是根据 getClass().getName() 进行分支。但是,我想知道多态性是否可以使用重载实现相同的行为:

public class Main
{
    static class A{}
    static class B extends A{}

    public static void foo(A a) { System.out.println("A"); };
    public static void foo(B b) { System.out.println("B"); };

    static A oracle()
    {
        return (Math.random() > 0.5) ? new A() : new B();
    }

    public static void main(String[] args)
    {
        A x = oracle();
        foo(x);
    }
}

这总是输出“A”,我怀疑这是由于用于解决函数调用的早期绑定。有人可以承认这一点吗?

4

5 回答 5

3

用技术术语来说,Java 是一种单调度OOP 语言。这意味着运行时决定调用哪个方法(方法分派)只考虑第一个方法参数——点左边的那个。在那里你可以看到这个原则是如何深深地根植于语言中,以至于第一个参数甚至得到了特殊的句法处理。

因此,不,您不能通过重载来完成运行时多态性。

于 2013-05-28T16:28:46.867 回答
2

这篇文章很好地解释了正在发生的事情:Overloading is compile-time binding

我认为您将要做的是instanceof在您的方法中实现代码以foo区别对待每种类型。

关于你的getClass().getName()断言,你永远不应该这样做。这就是instanceof目的。从更具体到不太具体的工作(即从 B 开始,然后是 A)。

于 2013-05-28T16:20:48.600 回答
1

这是因为foo(A a)是具有完全相同的方法签名的函数,所以它会使用那个。

在这种情况下,这foo(B b)绝不是一个有效的选择,因为您需要进行反思才能意识到它可能是一种合适的方法。Java 不会对所有参数使用反射来查看方法是否最终匹配,这太耗时了。

如果你想调用不同的方法,那么你应该使用类继承或其他多态技术。

于 2013-05-28T16:14:37.130 回答
0

尝试

static class A {
    public void foo() {
        System.out.println("A");
    }
}

static class B extends A {
    public void foo() {
        System.out.println("B");
    }
}


public static void main(String[] args) {
    A x = oracle();
    x.foo();
}

成员函数知道它们所属的类型。

于 2013-05-28T16:16:55.387 回答
0

您需要将 foo 方法作为 A 和 B 类中的实例方法。然后在您的情况下使用 B 对象的实例调用 x.foo() 应该会给您结果“B”。

于 2013-05-28T16:15:42.937 回答