Поддерживает ли Java динамический вызов метода? - PullRequest
3 голосов
/ 09 апреля 2010
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 не поддерживает динамический вызов метода. Есть три поддерживаемых режима вызовов: invokestatic, invokespecial, invokeinterface или invokevirtual. Эти режимы позволяют вызывать методы с известной подписью. Мы говорим о строго типизированный язык. Это позволяет чтобы сделать некоторые проверки непосредственно в время компиляции.

С другой стороны, динамический языки используют динамические типы. Так что мы можем вызвать метод, неизвестный при компиляции время, но это совершенно невозможно с байт-кодом Java.

Чего мне не хватает?

Ответы [ 5 ]

13 голосов
/ 09 апреля 2010

Вы путаете динамический вызов с динамическое связывание ..

Первый позволяет контроллеру типов принимать программы, в которых вы не уверены, будет ли метод присутствовать на объекте во время выполнения, тогда как динамическое связывание просто выбирает правильную реализацию в соответствии с типом времени выполнения объекта но с сохранением статической проверки типов .

Что это значит?

Это означает, что в вашем примере Java будет вызывать реализацию для объекта B, поскольку тип времени выполнения переменной objA равен B; и он скомпилируется, потому что знает, что B - это A, поэтому вызов метода не будет завершен неудачно во время выполнения (objA наверняка будет иметь реализацию F). *

Вместо этого при динамическом вызове он не будет проверять во время компиляции, что тип объекта, для которого вы вызываете F, содержит этот метод, конечно, он вызовет исключение, если во время выполнения метод не будет доступен на указанном объекте.

Только для мелочей: функция invokedynamic будет добавлена ​​с Java7, потому что многие языки сценариев были написаны для работы поверх JVM, а отсутствие функции динамического вызова вынудило разработчиков этих языков добавить средний уровень между скрипт и реальная JVM, которая заботится о динамическом вызове с использованием отражения. Конечно, такой подход приводит к большим накладным расходам (подумайте о MetaClass Грови), поэтому Sun решила им помочь.

1 голос
/ 09 апреля 2010

На самом деле, вам не хватает того, что это часть invokevirtual, которая описана в статье.

Вы просто переопределяете метод, который использует таблицу виртуальных методов для вызова правильного метода.

1 голос
/ 09 апреля 2010

В вашем примере вызывается правильный метод, потому что полиморфно экземпляр B выглядит как экземпляр A. Метод может быть найден путем проверки типа времени выполнения объекта; то есть B; в отличие от типа ссылки на объект во время компиляции, A. Другая важная часть - это сигнатура метода - они всегда должны совпадать (конечно, полиморфно).

Это отличается от динамических языков, потому что в тех, которые по существу не имеют времени компиляции для объекта - и все должно быть решено во время выполнения.

0 голосов
/ 16 ноября 2015

Вы можете сделать функциональные интерфейсы.

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

  // ...
}
0 голосов
/ 09 апреля 2010

Я бы не назвал ваш пример " динамический ", а скорее виртуальный .Потому что во время компиляции имя метода и сигнатура известны (и его существование проверяется компилятором).Единственное, что разрешается во время выполнения, - это конкретная реализация, которая будет использоваться для этого метода.

Более правильный пример «динамического» вызова метода будет включать отражение (см. Класс Method).Таким образом, методы, существование которых неизвестно при типе компиляции, могут быть вызваны во время выполнения (это широко используется фреймворками, а не прикладным кодом).,Но это правда, что сигнатура методов, которые вы явно вызываете, должна быть известна / проверена во время компиляции, и поэтому в этом смысле Java не является динамической.

...