【问题标题】:Java Inheritance and Method DispatchJava 继承和方法分派
【发布时间】:2018-04-21 01:18:59
【问题描述】:

鉴于此 Java 代码:

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

class B {
public void foo (String o) { System.out.println("B"); }
}

class C extends A {
public void foo (String s) { System.out.println("C"); }
}

class D extends B {
public void foo (Object o) { System.out.println("D"); }
}

class Main {
public static void main(String[] args) {
  A a = new C(); a.foo("Java"); 
  C c = new C(); c.foo("Java"); 
  B b = new D(); b.foo("Java"); 
  D d = new D(); d.foo("Java");
  } 
}

为什么结果是ACBB? 我将尝试解释我的想法,如果有人让我知道我的差距在哪里,我将不胜感激。

所以我对前两个电话的想法是:

  • a 具有静态类型 A,但动态类型为 C,因此 Java 应动态调度方法调用并在 C 打印“C”中调用 foo()

  • c有静态和动态类型C,所以既然我们继承自A,就必须选择最具体的方法,即public void foo(String s),从而打印“C”

  • b 具有静态类型 B 但动态类型 D 因此在这种情况下它也应该动态调度并在 D 中调用 foo() 并打印“D”。

    李>
  • d有静态和动态类型D,所以既然我们继承自B,就必须选择最具体的方法,即public void foo(String o),从而打印“B”

我在这里给出的这个解释有什么问题?

【问题讨论】:

    标签: java methods dynamic static overloading


    【解决方案1】:

    foo(Object) 不会覆盖 foo (String),而是重载它。因此D 有 2 种方法,由于将使用最具体的方法,因此当您传递字符串参数时它将是 foo(String)

    来自JLS 15.12.2(我强调):

    此步骤使用方法的名称和参数表达式来定位可访问且适用的方法,即可以在给定参数上正确调用的声明。

    这样的方法可能不止一种,在这种情况下,选择最具体的一种

    【讨论】:

    • 我玩过它,我明白你的意思。所以每当我有A a = new C() 并调用a.foo("Hello") 时,我可以确定只有静态类型的方法会得到解决,对吗?因为只有在我们重写 C 中的方法时才会发生调度。这个说法正确吗?
    • @DevX10 我会这样说:调度(我的理解)在任何情况下都会发生 2 次:1)在编译器选择最佳匹配方法签名时(在在 A 类型的变量上调用 foo("Java") 的情况,这将是 foo(Object),因为这是唯一可见的方法签名)和 2)在运行时,JVM 根据实际类型选择该签名的适当实现调用该方法的对象(即应该在您的示例中调用C 覆盖foo(Object) 覆盖版本)。
    【解决方案2】:

    A a = new C(); a.foo("Java");a调用foo(String)方法,这是一个A
    C c = new C(); c.foo("Java");c调用foo(String)方法,这是一个C
    B b = new D(); b.foo("Java");调用@来自 b 的 987654330@ 方法,这是一个 B
    D d = new D(); d.foo("Java"); 调用来自 dfoo(String) 方法,仅存在于 BD 包含 foo(Object) )

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-18
      • 1970-01-01
      • 1970-01-01
      • 2016-09-01
      • 2015-01-20
      • 1970-01-01
      • 2012-04-25
      • 1970-01-01
      相关资源
      最近更新 更多