【问题标题】:Polymorphism and Overloading多态性和重载
【发布时间】:2013-05-28 16:05:20
【问题描述】:

我最近遇到了以下场景:

我有一个超类 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”,我怀疑这是由于用于解决函数调用的早期绑定。有人可以承认这一点吗?

【问题讨论】:

  • 你传递给它一个A类型的变量,所以它调用签名为A的方法。我认为唯一的方法是使用你提到的getClass().getName()
  • @iamnotmaynard 我会把它写下来作为解决方案(也许更冗长一些)。
  • 没错。如果您绝对必须,您可以使用instanceof 运算符来打开实际的对象类型。但是将foo() 放在类 A 和 B 中更好的 OO 设计(这样对象就知道要“说”什么)
  • 但是对象知道它的类型,如果我调用 B 覆盖的成员函数,它会起作用。
  • 您可以尝试强制转换为 B,如果抛出异常,它就是 A ... 臭 :( 如果无法将成员函数添加到A 和 B。

标签: java polymorphism overloading


【解决方案1】:

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

因此,不,您无法通过重载实现运行时多态性。

【讨论】:

    【解决方案2】:

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

    我认为你要做的是在你的 foo 方法中实现 instanceof 代码 以不同的方式对待每种类型。

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

    【讨论】:

    • 好的,我认为这很好地总结了这里许多人所说的话。如果可能,在AB 中包含成员函数会更优雅,否则instanceof 是唯一的选择。
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • OP 说这不是一个选项
      【解决方案5】:

      试试

      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();
      }
      

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

      【讨论】:

      • "[...] 但我不能为 A 和 B 引入新的成员函数"
      • 正是我要写的:) +1
      • OP 说这不是一个选项
      • 我知道这行得通,但我不能像上面解释的那样引入成员类。
      • extend上课怎么样?
      猜你喜欢
      • 2017-01-02
      • 2019-11-07
      • 2011-06-25
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-06
      • 1970-01-01
      相关资源
      最近更新 更多