Одна проблема заключается в том, что «то, что JVM фактически сделала с ним», изменяется между вызовами, поскольку JVM может свободно генерировать код.
В качестве примера я несколько дней назад исследовал, что Hotspot делает с final
методы по сравнению с виртуальными методами.Судя по микробенчмаркам, я сделал следующие выводы:
Клиентская JVM: если метод эффективно final
(нет ни одного загруженного класса, который переопределяет его),JVM использует не виртуальный вызов.Впоследствии, если вы загрузите класс, который переопределяет этот метод, 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
}
Если вы действительно заинтересованы в просмотре сгенерированного кода, вы можете поиграть с JVM DEBUG из OpenJDK:
http://dlc.sun.com.edgesuite.net/jdk7/binaries/index.html
http://wikis.sun.com/display/HotSpotInternals/PrintAssembly