E fin qui, f1 e' di classe A e punta a un oggetto di classe A. Quindi stampa A.codice:f1 = new A(); f2 = new B(); f3 = new C(); f1.message();
Ora f1 (di classe A, che credo sia quello che chiami static type) punta a f2, oggetto di classe B (che dovrebbe essere quello che chiami dynamic type) per cui sara' eseguito il metodo message della classe B, stampando B.codice:f1=f2; f1.message();
Questo e' quello che si chiama binding dinamico: nonostante f1 sia di tipo A, e' stato richiamato il metodo della classe B.
Per lo stesso motivo qua viene stampato C.codice:f1=f3; f1.message();
Questo metodo richiama il metodo message della superclasse. Siccome f2 punta a un oggetto di classe B e la superclasse di B e' A, sara' eseguito il metodo message() della classe A, stampando A.codice:f2.message_from_a();
Questo stampa C, ovviamente.codice:f3.message();}
P.S. Lo static type e' un concetto che, credo, derivi dal C++ ma ha poco senso applicato a Java, dove viene usato piu' che altro dal compilatore per il type checking.