Java支持动态方法调用吗?

Java支持动态方法调用吗?,java,dynamic,bytecode,dynamic-method,Java,Dynamic,Bytecode,Dynamic Method,在这里,F()正在被动态调用,不是吗 说: 。。。Java字节码不支持 动态方法调用。有 三种支持的调用模式: invokestatic,invokespecial, invokeinterface或invokevirtual。 这些模式允许调用方法 有已知的签名。我们谈论 强类型语言。这允许 直接在 编译时 另一方面,动态 语言使用动态类型。所以我们可以 在编译时调用未知的方法 时间,但那是完全不可能的 使用Java字节码 我缺少什么?您将动态调用与动态绑定混为一谈 第一种方法允许类型检查器接

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

说:

。。。Java字节码不支持 动态方法调用。有 三种支持的调用模式: invokestatic,invokespecial, invokeinterface或invokevirtual。 这些模式允许调用方法 有已知的签名。我们谈论 强类型语言。这允许 直接在 编译时

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

我缺少什么?

您将动态调用与动态绑定混为一谈

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

这是什么意思

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

相反,使用动态调用时,它不会在编译时检查调用
F
的对象的类型是否包含该方法,当然,如果在执行期间该方法在指定对象上不可用,它将引发异常


只是为了琐事:
invokedynamic
特性将与Java7一起添加,因为许多脚本语言都是在JVM之上编写的,而动态调用特性的缺乏迫使这些语言的开发人员在脚本和真正的JVM之间添加一个中间层,它使用反射当然,这种方法会导致大量开销(想想Grovvy的
元类
),这就是Sun决定给他们提供帮助的原因。

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


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

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


您只是覆盖了该方法,并使用虚拟方法表来调用正确的方法。

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

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


你提到的那篇文章在这方面似乎有点误导。但确实,您显式调用的方法的签名必须在编译时已知/检查,因此,从这个意义上说,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();
    }
}
类记录器{
专用双消费者记录器=null;
// ...
专用记录器(对象记录器){
this.akkaLogger=(LoggingAdapter)记录器;
this.logger=(消息,级别)->{
开关(电平){
案例信息:akkaInfo(信息);
打破
案例调试:akkaDebug(消息);
打破
案例错误:akkaError(消息);
打破
案例警告:akkaWarn(信息);
打破
}
};
}
专用记录器(){
this.logger=(消息,级别)->System.out.println(消息);
}
// ...
}

运行程序时会发生什么?这篇文章的作者需要上一堂计数课。
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);
  }

  // ...
}