O elemento chave nisso é a separação da compilação da fase de execução. Com isso, é possível escrever outros compiladores compilando outros idiomas no bytecode.
O bytecode atua de maneira semelhante ao código de máquina de uma CPU - você tem todas as pequenas operações necessárias para executar um programa - você pode obter uma variável, fazer contas nela, realizar operações condicionais etc.
Java também não é especial. Em Java, a existência de várias linguagens não era nem uma meta de design, ao contrário de outras VMs. Para o .Net CIL da Microsoft, a capacidade de executar vários idiomas (C #, VB.Net, ...) era um elemento-chave de design, também o ParrotVM do projeto Perl6 pretendia ser uma VM genérica.
Por diversão, criei uma prova de que até o Zend Engine do PHP permitiria isso.
E, francamente, isso não é novidade - mesmo em hardware real, você pode executar vários idiomas - ou seja, C ou Fortran.
A diferença para essa separação da compilação e execução são os intérpretes clássicos, como algumas formas de Basic, scripts de shell etc. Eles geralmente funcionam de maneira a executar código mais ou menos linha por linha, sem trazê-lo de forma imediata. entre.