Ciao,
a breve ho l'esame di linguaggi di programmazione...ho un piccolo dubbio circa una questione teorica riguardante come funziona il polimorfismo in Java.

Praticamente da quello che ho capito il polimorfismo più genuino possibile è il cosidetto polimorfismo universale in cui una variabile (o una routine) può assumere una qualsiasi possibile forma.

Tuttavia Java per essere type safe adotta una restrizione a tale polimorfismo che viene detta POLIMORFISMO PER INCLUSIONE ed è basato sul meccanismo dell'ereditarietà mediante il quale è possibile definire sottotipi definendo delle sottoclassi.
In tale tipo di polimorfismo, dati un tipo T ed un suo sottotipo S, valgono le seguenti regole:

1) Gli oggetti di tipo S sono particolari oggetti di tipo T che devono soddisfare un certo numero di vincoli aggiuntivi (ad esempio ho una classe padre Rettangolo ed una classe figlia Quadrato...in quest'ultima c'è il vincolo aggiuntivo che base ed altezza devono essere uguali).

2) Tutti gli operatori del supertipo T sono anche operatori definiti per il sottotipo S, viceversa possono esistere operatori definiti per il sottotipo S che non sono definiti per il supertipo T (per esempio Quadrato potrebbe saper fare delle cose in più di Rettangolo come calcolare l'area del cerchio inscritto)

3) Taluni operatori definiti per il supertipo T hanno un comportamento diverso nel sottotipo e li devo andare a ridefinire nel sottotipo S mantenendo la stessa signature (è questo l'overriding degli operatori?).

Tramite il polimorfismo per inclusione posso definire una variabile di un certo tipo T e di ASSEGNARLE SOLTANTO IL RIFERIMENTO AD UN OGGETTO IL CUI TIPO è T O UN QUALUNQUE SOTTOTIPO DI T.

Possiamo ad esempio definire un metodo la cui signature sarà: nomeMetodo(T parametro) e poi, in qualche altro metodo, invovarlo passandogli come parametro attuale il riferimento ad un oggetto di tipo S dove S è sottotipo di T.
Da qua deriva che il compilatore non è in grado di conoscere i tipi effettivi dei parametri attuali che sono potenzialmente infiniti (perchè potrei derivare infiniti tipi di dato da un tipo T).

Nonostante il compilatore non sia in grado di conoscere i tipi effettivi degli oggetti è comunque STRONGLY TYPED e ciò è reso possibile proprio dalla restrizione imposta sull'uso delle variabili polimorfiche: "Una volta dichiarata una variabile di un tipo T, all'oggetto referenziato da quella variabile possono essere inviati solo messaggi il cui contenuto è un operatore del tip T e non di qualche suo sottotipo".

Per esempio nel main potrei avere qualcosa del genere:

codice:
Rettangolo R = new Quadrato(2);  // Definisco R come quadrato ma lo creo come Rettangolo

double d = R.raggioCerchioInscritto();
Ed infatti la seconda istruzione darà errore di compilazione perchè il type checking avviene staticamente...

Ok...già quà ho il primo dubbio: praticamente che significa esattamete sta cosa? Semplicemente che ad un metodo definito in Rettangolo posso passare come parametro anche un elemento di tipo Quadrato ma che se dichiaro una variabile di tipo Rettangolo e la creo come Quadrato posso usare solo i metodi definiti in Rettangolo?
(non è molto limitante questa cosa? non mi torna...)
Tra l'altro se io dichiaro una variabile del supertipo Rettangolo e la creo come Quadrato non gli stò passando un messaggio che contiene il costruttore di Quadrato che è un metodo di Quadrato?!?!
Se dichiaro sempre R come Rettangolo ma poi lo costruisco come Quadrato e nella classe figlio ho ridefinito dei metodi presenti nella classe padre...vengono usati i metodi della classe padre?

Poi c'è la seconda cosa che non mi torna per niente

Mi dice che il polimorfismo in JAVA è particolarmente utile in quanto la JVM esegue il binding dinamico (a runtime) tra invocazioni dei metodi e corpo dei metodi invocati...cioè se in una classe che contiene il main() avessi qualcosa come:

codice:
Rettangolo R;     // Dichiaro R come supertipo Rettangolo

if(Math.random()>0)        // Se esce un numero positivo
      R = new Rettangolo;  // allora lo crea come Rettangolo
else
      R = new Quadrato;    // altrimenti lo crea come il sottotipo Quadrato

R.allarga(4);
La proff dice che si nota che il TIPO EFFETTIVO del rettangolo R è noto solo a runtime in quanto dipende dalla generazione del numero casuale e dice che se il binding tra l'invocazione del metodo allarga ed il codice avenisse staticamente allora l'istruzione R.allarga(4) causerebbe l'invocazione del metodo allarga() definito nella classe Rettangolo e quindi se il tipo effettivo referenziato da R fosse Quadrato si invocherebbe il metodo sbagliato.

Invece in JAVA è la JVM a fare questo binding dinamicamente ed invoca il metodo della classe Quadrato e lo fà in questo modo: controlla il tipo effettivo dell'oggetto referenziato da R ed invoca il metodo allarga() definito per il tipo effettivo che è Quadrato...

Ma questo non và palesemente in contrasto con quanto detto prima?!?!
Mi riferisco alla restrizione imposta sull'uso delle variabili polimorfiche: "Una volta dichiarata una variabile di un tipo T, all'oggetto referenziato da quella variabile possono essere inviati solo messaggi il cui contenuto è un operatore del tip T e non di qualche suo sottotipo".

Come funziona?!?! Mi pare che le due cose siano in conflitto e si contraddicano palesemente...

Vi prego aiutatemi sono abbastanza disperato

Grazie
Andrea VVoVe: