Java支持动态方法调用吗?

发布于 2024-08-28 11:15:52 字数 711 浏览 9 评论 0原文

class A           { void F() { System.out.println("a"); }}
class B extends A { void F() { System.out.println("b"); }}

public class X {
    public static void main(String[] args) {
        A objA = new B();
        objA.F();
    }
}

这里,F() 正在被动态调用,不是吗?

本文说:

... Java 字节码不支持 动态方法调用。有 三种支持的调用模式: 调用静态、调用特殊、 调用接口或调用虚拟。 这些模式允许调用方法 具有已知签名。我们谈论 强类型语言。这允许 直接进行一些检查 编译时间。

另一方面,动态 语言使用动态类型。所以我们可以 调用编译时未知的方法 时间,但这完全不可能 与 Java 字节码。

我错过了什么?

class A           { void F() { System.out.println("a"); }}
class B extends A { void F() { System.out.println("b"); }}

public class X {
    public static void main(String[] args) {
        A objA = new B();
        objA.F();
    }
}

Here, F() is being invoked dynamically, isn't it?

This article says:

... the Java bytecode doesn’t support
dynamic method invocation. There are
three supported invocations modes :
invokestatic, invokespecial,
invokeinterface or invokevirtual.
These modes allows to call methods
with known signature. We talk of
strongly typed language. This allows
to to make some checks directly at
compile time.

On the other side, the dynamic
languages use dynamic types. So we can
call a method unknown at the compile
time, but that’s completely impossible
with the Java bytecode.

What am I missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜是你 2024-09-04 11:15:52

您将动态调用动态绑定混淆了。

第一个允许类型检查器接受您不确定对象上是否存在方法的程序运行时,而动态绑定只是根据对象的运行时类型选择正确的实现但保持静态类型检查

这是什么意思?

这意味着在您的示例中,Java 将调用对象 B 上的实现,因为 objA 变量的运行时类型是 B;它会编译,因为它知道 B A 因此方法调用在运行时不会失败 (objA< /code> 肯定会有一个 F 实现)。

相反,使用动态调用时,它不会在编译时检查您调用 F 的对象的类型是否包含该方法,当然,如果在执行过程中该方法不包含该方法,则会引发异常可用于指定对象。

简单说一下:Java7 中将添加 invokedynamic 功能,因为许多脚本语言都是在 JVM 之上编写的,而动态调用功能的缺乏迫使这些语言的开发人员添加中间层脚本和真正的 JVM 之间的层,关心使用反射的动态调用。当然,这种方法会导致大量开销(想想 Grovvy 的 MetaClass),这就是 Sun 决定为他们提供帮助的原因。

You are confusing dynamic invocation with dynamic binding..

The first one allows the type checker to accept programs in which you are not sure if a method will be present on an object at run-time, while dynamic binding just chooses the right implementation according to the runtime type of the object but maintaining the statically type checking.

What does it mean?

It means that in your example, Java will call the implementation on object B because the runtime type of the objA variable is B; and it will compile because it knows that a B is a A so the method invocation won't fail at runtime (objA will have a F implementation for sure).

With dynamic invocation instead it won't check at compile time that the type of the object on which you are calling F contains that method, of course it will raise an exception if during execution the method won't be available on specified object.

Just for trivia: the invokedynamic feature will be added with Java7 because many scripting languages have been written to work on top of JVM and the lack of a dynamic invocation feature forced the developers of these languages to add a middle layer between the script and the real JVM that cares about dynamic invocation using the reflection. Of course this approach causes a lot of overhead (think about Grovvy's MetaClass), that's why Sun decided to give them a help..

缺⑴份安定 2024-09-04 11:15:52

在您的示例中,调用了正确的方法,因为从多态性来看,B 的实例看起来像 A 的实例。可以通过检查对象的运行时类型来定位该方法;即B;与对象引用的编译时类型相反,A。另一个重要部分是方法的签名 - 这些必须始终匹配(当然是多态的)。

这与动态语言不同,因为在动态语言中,对象基本上没有编译时 - 并且所有内容都必须在运行时解决。

In your example the correct method is called because polymorphically the instance of B appears like an instance of A. The method can be located by examining the runtime type of the object; that is, B; as opposed to the compile-time type of the object reference, A. The other important part is the signature of method - these must always match (polymorphically of course).

This differs from dynamic languages because in those there is essentially no compile-time for the object - and everything must be resolved at runtime.

花桑 2024-09-04 11:15:52

事实上,您缺少的是这是文章中解释的“invokevirtual”的部分。

您只需重写该方法并使用虚拟方法表来调用正确的方法。

In fact, what you're missing is that this is the part of 'invokevirtual' which is explained in the article.

You're simply overriding the method and that uses a virtual method table to invoke the correct method.

多像笑话 2024-09-04 11:15:52

我不会将您的示例称为“动态”,而是“虚拟”。因为在编译时方法名称和签名是已知的(并且编译器检查其存在)。在运行时唯一解决的是该方法要使用的具体实现。

“动态”方法调用的一个更合适的示例将涉及反射(请参阅 Method 类)。通过这种方式,可以在运行时调用编译类型中未知的方法(这在框架中广泛使用,但在应用程序代码中使用不多)。

您提到的文章在这方面似乎有点误导。但确实,您显式调用的方法的签名必须在编译时已知/检查,因此,从这个意义上说,Java 不是动态的。

I wouldn't call your example "dynamic", rather virtual. Because at compile time the method name and signature is known (and its existence is checked by the compiler). The only that is resolved at runtime is the concrete implementation to be used for that method.

A more proper example of "dynamic" method invocation would involve reflection, (see the Method class ). In that way, methods whose existence are unkown at compile type can be invoked in runtime (this is extensively used by frameworks, not so much by application code).

The article you mention seems a little misleading in that respect. But it's true that the signature of the methods you explicitly call must be known/checked in compile time, and so, in that sense, Java is not dynamic.

私藏温柔 2024-09-04 11:15:52

您可以制作函数式接口。

class Logger {
  private BiConsumer<Object, Integer> logger = null;

  // ...

  private Logger(Object logger) {
      this.akkaLogger = (LoggingAdapter) logger;
      this.logger = (message, level) -> {
          switch (level) {
              case INFO:  akkaInfo(message);
                          break;
              case DEBUG: akkaDebug(message);
                          break;
              case ERROR: akkaError(message);
                          break;
              case WARN:  akkaWarn(message);
                          break;
          }
      };
  }

  private Logger() {
      this.logger = (message, level) -> System.out.println(message);
  }

  // ...
}

You can make functional interfaces.

class Logger {
  private BiConsumer<Object, Integer> logger = null;

  // ...

  private Logger(Object logger) {
      this.akkaLogger = (LoggingAdapter) logger;
      this.logger = (message, level) -> {
          switch (level) {
              case INFO:  akkaInfo(message);
                          break;
              case DEBUG: akkaDebug(message);
                          break;
              case ERROR: akkaError(message);
                          break;
              case WARN:  akkaWarn(message);
                          break;
          }
      };
  }

  private Logger() {
      this.logger = (message, level) -> System.out.println(message);
  }

  // ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文