Das Schlüsselelement dabei ist die Trennung der Kompilierung von der Ausführungsphase. Auf diese Weise ist es möglich, andere Compiler zu schreiben, die andere Sprachen zu Bytecode kompilieren.
Bytecode dort verhält sich ähnlich wie der Maschinencode einer CPU - Sie haben alle kleinen Operationen, die zum Ausführen eines Programms erforderlich sind - Sie können eine Variable abrufen, rechnen, bedingte Operationen ausführen usw.
Java ist auch nichts Besonderes. In Java war das Vorhandensein mehrerer Sprachen im Gegensatz zu anderen VMs nicht einmal ein Entwurfsziel. Für Microsoft .Net CIL war die Möglichkeit, mehrere Sprachen (C #, VB.Net, ...) auszuführen, ein wichtiges Designelement, und auch ParrotVM aus dem Perl6-Projekt sollte eine generische VM sein.
Zum Spaß habe ich mal einen Beweis erstellt, dass selbst die Zend Engine von PHP das zulässt.
Und ehrlich gesagt ist dies nichts Neues - selbst auf echter Hardware können Sie mehrere Sprachen ausführen - z. B. C oder Fortran.
Der Unterschied zu dieser Trennung von Kompilierung und Ausführung besteht darin, dass CLSSIC-Interpreter, wie einige Formen von Basic, Shell-Skripten usw., häufig so arbeiten, dass sie Code mehr oder weniger zeilenweise ausführen, ohne ihn in eine unmittelbare Form zu bringen zwischen.