O byte-code que o nosso colega se referiu acima existe sim, ele é uma pré-compilação.
Entendendo melhor, quem faz o papel da máquina nessa história é o JVM, cada plataforma possui um JVM, Linux, Windows, Unix até Mac OS. Todos os byte-codes gerados são iguais, pois quem deve entendê-los é o JVM e não o Hardware físico da máquina. Como já foi dito em uma mensagem anterior, o JVM interpreta o byte-code, pois o mesmo não é compilado... essa pré-compilação apenas transforma a código do programador em um nível um pouco mais baixo para facilitar a compreensão por parte do JVM. O byte-code não deixa de ser uma espécie de "assembler", pois não é um arquivo binário, porém só pode ser interpretado pelo JVM.
O Java até que eu saiba não faz nenhuma compilação completa, ou seja, não gera um arquivo binário nativo de um determinado SO, e é até por isso que o Java não é tão perfeito, pois o preço que se paga nesse processo de interpretação, etc... é o tempo. Um programa Java é muito mais lento que outro qualquer que possua um .exe por causa desse processo, em compensação Java roda em várias outras plataformas.