Basicamente funciona da mesma forma, mas na hora de gerar o bytecode ele faz uma série de checagens e conversões, usando Iterator para percorrer a lista.
No livro da Keith Sierra (SCJP 1.6) explica em mais detalhes.
Com o forreach surgiu a facilidade de percorrecor os elementos de um array ou uma lista.
Exemplo sem o foreach:
String[] nomes = new String[] {“Jose”, “Antonio”}; //Uma variavel array que tem 2 nomes
for (int i = 0; i < nomes.length; i++) { // For que percorre as posições do array
System.out.println(nomes[i]);
}
Exemplo com foreach:
String[] nomes = new String[] {“Jose”, “Antonio”}; //Um variavel arry que tem 2 nomes
for (String valor : nomes) { //Aqui é que está toda a "mágica". Você declara uma variável correspondente aos valores
//armazenados no array inseri ":" e passa a variável array como parametro.
System.out.println(valor);
}
Agora o foreach só pode ser utilizado para percorrer os elementos e não para atribuir algum valor.
OBS: O foreach pode ser utilizado para percorrer array ou qualquer tipo de lista.