Некоторые из них генерируют байт-код. У некоторых есть система времени выполнения, которая выполняется как интерпретатор. У некоторых есть смесь двух. В конце концов, JVM - это процессор (который на самом деле не существует) с определенной архитектурой и определенным набором инструкций. Вы выбираете его с помощью генератора кода так же, как вы генерируете объектный код для любого процессора. (Теперь, чтобы быть справедливым, его набор инструкций очень сильно сфокусирован на возможностях и потребностях Java, но все же достаточно универсален, чтобы поддерживать другие модели.
Существует множество способов генерации байт-кода JVM. Вы можете управлять своими собственными процедурами генерации файлов .class (поскольку формат и набор инструкций хорошо определены ). Вы можете использовать несколько библиотек, таких как ASM или BCEL (я думаю, это наиболее распространенный подход). Или вы можете сгенерировать код Java в качестве промежуточного представления, а затем скомпилировать его с помощью обычных инструментов Java.
Вы выполняете код так же, как и код, скомпилированный с Java: среда выполнения Java загружает сгенерированные файлы .class и запускается. Это тоже часть спецификации .