Одна проблема заключается в том, что «то, что JVM фактически сделал для него» изменений между вызовами как JVM волен повторно генерировать код.
В качестве примера я несколько дней назад исследовал, что Hotspot делает с final
методами по сравнению с виртуальными методами. Судя по microbenchmarks, мои выводы были:
Клиента JVM: Если метод эффективноfinal
(нет никакого загруженного класса, который перекрывает его), виртуальная машина использует невиртуальный вызов. Впоследствии, если вы загружаете класс, который переопределяет этот метод, JVM изменит код JIT, чтобы сделать виртуальные вызовы. Поэтому объявление final
не имеет существенной значимости.
Сервер JVM: здесь final
также не имеет отношения. Кажется, что JVM генерирует не виртуальный вызов для любого класса, в котором вы используете в первый раз, независимо от того, какие классы загружены. Впоследствии, если вы сделаете вызов с объекта другого класса, JVM будет исправлять все вызовы с чем-то похожим на это (я думаю, что он будет также выполнять профильные вызовы, чтобы он мог изменять быстрый и медленный путь, если он не получил это право в первый раз):
if (object instanceof ClassOfNonVirtualCall) {
do non-virtual call to ClassOfNonVirtualCall.method
} else {
do virtual call to object.method
}
Если вы действительно заинтересованы в том, чтобы сгенерированный код, вы можете играть с DEBUG от OpenJDK виртуальных машинах:
http://dlc.sun.com.edgesuite.net/jdk7/binaries/index.html
http://wikis.sun.com/display/HotSpotInternals/PrintAssembly
Действительно, VM будет встроен специальный код для двух классов - биморфная вставка. Я считаю, что эта функция была реализована для поддержки NIO direct и Java heap buffers. –