Как Java-интерфейсы реализованы внутри?(виртуальные таблицы?) - PullRequest
38 голосов
/ 12 декабря 2010

C ++ имеет множественное наследование. Реализация множественного наследования на уровне сборки может быть довольно сложной, но есть хорошие описания онлайн о том, как это обычно делается (vtables, исправления указателей, thunks и т. Д.).

Java не имеет множественного наследования реализации, но имеет множественное наследование интерфейса, поэтому я не думаю, что прямая реализация с одним виртуальным столом на класс может это реализовать. Как Java реализует интерфейсы внутри?

Я понимаю, что в отличие от C ++, Java компилируется Jit, поэтому разные части кода могут быть оптимизированы по-разному, а разные JVM могут работать по-разному. Итак, существует ли какая-то общая стратегия, которой придерживаются многие JVM, или кто-нибудь знает реализацию в конкретной JVM?

Кроме того, JVM часто девиртуализируют и вызывают встроенные вызовы методов, и в этом случае вообще нет задействованных vtables или эквивалентов, поэтому может не иметь смысла спрашивать о фактических последовательностях сборки, которые реализуют вызовы виртуальных / интерфейсных методов, но я предполагаю, что большинство JVM по-прежнему сохраняйте какое-то общее представление о классах, чтобы они могли использовать их, если они не смогли деватуризировать все. Это предположение неверно? Это представление выглядит как C ++ vtable? Если да, то есть у интерфейсов есть отдельные vtables и как они связаны с vtables класса? Если это так, могут ли экземпляры объектов иметь несколько указателей vtable (на vtables классов / интерфейсов), как экземпляры объектов в C ++? Всегда ли ссылки на тип класса и тип интерфейса на один и тот же объект имеют одинаковые двоичные значения или могут отличаться, как в C ++, где они требуют исправления указателя?

(для справки: этот вопрос задает что-то похожее в CLR, и в этой статье MSDN есть хорошее объяснение, хотя это может быть уже устаревшим. У меня нет Не удалось найти ничего подобного для Java.)

Edit:

  • Я имею в виду «реализует» в смысле «Как компилятор GCC реализует целочисленные добавления / вызовы функций / и т. Д.», А не в смысле «Java-класс ArrayList реализует интерфейс List».
  • Мне известно о том, как это работает на уровне байт-кода JVM, я хочу знать, какой тип кода и структур данных генерируется JVM после завершения загрузки файлов класса и компиляции байт-кода.

1 Ответ

27 голосов
/ 13 декабря 2010

Ключевой особенностью JSM HotSpot является встроенное кэширование . Это на самом деле не означает, что целевой метод является встроенным, но означает, что предположение помещается в код JIT, который будет направлен на каждый будущий вызов виртуального или интерфейсного метода та же самая реализация (то есть, что сайт вызова является мономорфным). В этом случае проверка компилируется в машинный код, действительно ли предположение верно (т.е. тип целевого объекта такой же, как это было в прошлый раз), а затем передать управление непосредственно к целевому методу - без каких-либо виртуальных таблиц. Если утверждение не выполнено, может быть предпринята попытка преобразовать его в мегаморфный сайт вызова (то есть с несколькими возможными типами); если это также не удается (или если это первый вызов), выполняется регулярный поиск по многим путям с использованием vtables (для виртуальных методов) и itables (для интерфейсов).

Редактировать : Hotspot Wiki содержит более подробную информацию о vtable и itable заглушках. В полиморфном случае он все еще помещает версию встроенного кэша в сайт вызовов. Однако код на самом деле является заглушкой, которая выполняет поиск в vtable, или itable. Существует одна заглушка vtable для каждого смещения vtable (0, 1, 2, ...). Интерфейсные вызовы добавляют линейный поиск по массиву itables перед просмотром itable (если он найден) с заданным смещением.

...