Java接口类型参数是如何工作的?

问题描述 投票:0回答:1

如果给定的类型是接口,Java 如何知道运行时的确切调用地址?例如,

// A few definitions

public interface In {
  void method();
}

public class A implements In {
  public void method() {
    System.out.println("A");
  }
}

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

有一些接口,类定义,使用如下。

// ... Java stuff...
public int main() {
  test1(new A()); // stdout A
  test2(new B()); // stdout A
}

public void test1(In i) {
  i.method();
}

public void test2(A a) {
  a.method();
}

从 test1 的结果来看,Java 运行时似乎知道给定

i
的类型原因
test1
打印出
A
main
作为参数给出。

test2的结果,如果给定的参数类型不是接口,Java运行时不知道给定的类型

B
,只能访问
A
的方法,实际上
main
没有给出。

第二种情况

test2
对我来说非常简单,因为编译器不知道
A
的哪个子类型作为参数给出,所以只需编译为字节码即可调用
A
的方法。所以运行时只是调用
A
的方法。

但是第一种情况

test1
,运行时如何准确知道给定类型是什么?

java compilation
1个回答
-1
投票

Java 基本上有 2 种方法来确定要运行的方法实现:

  1. 静态调度
  2. 动态调度

Static dispatch 是当你compile 代码时,Java 将查看你正在使用的变量的类型并为该类型选择方法。

然而,在动态调度中,执行什么方法的决定是由接收对象完成的,与任何类型的变量无关。这是在运行时完成的

所以你可以认为它是 Java“询问”对象 来执行选定的方法,然后 Java 对象查看它是否有那个方法,如果它没有在它的类中实现该方法“问”是超一流的。这个过程一直到层次结构的根类。

注意:在 Java 中,对象总是知道它们的类是什么。您可以调用像

object.getClass()
这样的方法。所以在内部你可以想象它利用了这个事实。

实际的实现细节可能稍微更细微,并且充满优化,但这是您可以使用的心智模型。

事实上,在 Smalltalk(第一种或第二种 OO 语言,取决于你问谁)中,这正是它发生的方式。 “方法调用”会向对象发送“消息”,对象会执行该方法或将其传递给超类。如果没有找到实现,你会得到一个异常(因为 Smalltalk 没有静态类型)。

这就是为什么动态调度有时被称为“消息传递”的原因。

© www.soinside.com 2019 - 2024. All rights reserved.