No: anim e' un riferimento a un oggetto di tipo Animale, che punta a un oggetto, prima di tipo Cane, poi di tipo Gatto. Ma il suo tipo rimane Animale.

Quello postato da te e' un esempio in cui il polimorfismo non viene sfruttato. Avresti potuto dichiarare una variabile di tipo Cane e una di tipo Gatto.

Scrivendo invece:

codice:
Animale[] anim = {new Cane(), new Gatto()};

for (i=0; i<anim.length; ++i)
   anim[i].emetteVerso();
si capisce l'utilita' del binding dinamico.

Se il tuo dubbio era solo sul fatto che il compilatore non ottimizza il codice, ricordati che Java e' un linguaggio orientato al multitasking. Nessuno ti assicura che la sequenza:

codice:
anim=new Cane();
anim.emetteVerso();
non venga interrotta dall'esecuzione di un altro thread che vada a modificare anim.