Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11
  1. #1
    Utente di HTML.it
    Registrato dal
    Jun 2004
    Messaggi
    643

    Domanda Teorica Sul Polimorfismo Per Inclusione Di Java Helpme

    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:

  2. #2
    Utente di HTML.it
    Registrato dal
    Mar 2002
    Messaggi
    137
    ma non si può ovviare al problema con l'overloading dei metodi?
    Certo è che per ogni possibile tipo devi riscrivere un metodo.
    $Pippo... la variabile preferita dall'ingegnere!

  3. #3
    Utente di HTML.it
    Registrato dal
    Jun 2004
    Messaggi
    643
    Si ma la domanda era un po' più complessa...nel senso che mi sembra che le cose che mi hanno detto si contraddicano palesemente.

    Riformuliamo il tutto in maniera veloce.

    Se io ho un supertipo definito dalla classe Rettangolo ed un sottotipo di tale classe definito dalla classe Quadrato (c'è una relazione "is a", nel senso che un quadrato è un rettangolo e deve soddisfare un vincolo in più: che i lati siano uguali). Dentro la classe Quadrato avrò alcuni metodi di Rettangolo riscritti ed alcuni metodi in più che esprimono cose che un quadrato sa fare e che un rettangolo non sa fare come il calcolo del raggio del cerchio iscritto ad un quadrato.

    Inizialmente mi si dice che in Java se nel main() avessi qualcosa del tipo:

    codice:
    Rettangolo R = new Quadrato();
    double d = R.raggioCerchioInscritto();
    mi verrà dato un errore in fase di compilazione poichè Java adotta una restrizione all'uso delle variabili polimorfiche che dice che una volta che dichiaro una variabile di tipo T (nel nostro esempio di tipo Rettangolo), agli oggetti referenziati da quella variabile posso inviare solomessaggi che contengono metodi di tipo T e non dei suoi possibili sottotipi.

    Quì mi viene detto chiaramente che l'invocazione del metoro raggioCerchioInscritto causerà un errore in fase di compilazione perchè tale metodo è definito solo nel sottotipo Quadrato ma la variabile, benchè sia stata costruita come Quadrato, è stata dichiarata di tipo Rettangolo.

    Poi mi viene detto che se nel main() avessi qualcosa del tipo:

    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);
    dove allarga è un metodo che esiste sia in Rettangolo, sia ridefinito in maniera appropriata in Quadrato...

    Mi si dice che se l'oggetto viene costruito a runtime come Rettangolo viene invocata la versione del metodo definita nella classe Rettangolo, mentre se l'oggetto viene costruito a runtime come Quadrato viene invocata la versione del metodo definita nella classe Quadrato....questo grazie alla JVM che esegue dinamicamente il binding tra invocazione del metodo e corpo del metodo invocante....

    Tutto molto bello...ma mi pare in chiara contraddizione con quanto detto nell'esempio precedente in quanto anche in questo secondo caso l'oggetto viene definito come Rettangolo (prima di essere costruito a runtime o come Rettangolo o come Quadrato)...

    Non dovrebbe valere quanto detto prima?!?! che se definisco la variabile R come Rettangolo anche se ci metto il riferimento ad un oggetto costruito come Quadrato (con tipo effettivo Quadrato) posso usare solo i metodi definiti in rettangolo per la famosa regola restrittiva sulle variabili polimorfe...

    O l'una o l'altra cosa sono sbagliate...perchè quà dichiaro R come Rettangolo e se poi lo costruisco come Quadrato posso usare la versione del metodo dilata() definita nella classe Quadrato e prima che dichiaravo sempre R come Rettangolo e poi lo costruivo come Quadrato mi dava errore in fase di compilazione se provavo ad eseguire il metodo raggioCerchioInscritto() definito solo nella classe Quadrato?!?!?

    E' questo che non mi torna

    Grazie
    Andrea

  4. #4
    Utente di HTML.it
    Registrato dal
    Mar 2002
    Messaggi
    137
    Originariamente inviato da D4rkAng3l
    Mi si dice che se l'oggetto viene costruito a runtime come Rettangolo viene invocata la versione del metodo definita nella classe Rettangolo, mentre se l'oggetto viene costruito a runtime come Quadrato viene invocata la versione del metodo definita nella classe Quadrato....questo grazie alla JVM che esegue dinamicamente il binding tra invocazione del metodo e corpo del metodo invocante....

    Tutto molto bello...ma mi pare in chiara contraddizione con quanto detto nell'esempio precedente in quanto anche in questo secondo caso l'oggetto viene definito come Rettangolo (prima di essere costruito a runtime o come Rettangolo o come Quadrato)...

    Non dovrebbe valere quanto detto prima?!?! che se definisco la variabile R come Rettangolo anche se ci metto il riferimento ad un oggetto costruito come Quadrato (con tipo effettivo Quadrato) posso usare solo i metodi definiti in rettangolo per la famosa regola restrittiva sulle variabili polimorfe...

    O l'una o l'altra cosa sono sbagliate...perchè quà dichiaro R come Rettangolo e se poi lo costruisco come Quadrato posso usare la versione del metodo dilata() definita nella classe Quadrato e prima che dichiaravo sempre R come Rettangolo e poi lo costruivo come Quadrato mi dava errore in fase di compilazione se provavo ad eseguire il metodo raggioCerchioInscritto() definito solo nella classe Quadrato?!?!?

    E' questo che non mi torna

    Grazie
    Andrea
    Premetto che non sono ancora molto pratico del Java.
    Ma stante le tue definizioni se tu invece del metodo allarga() richiamassi il solito metodo raggiocerchioinscritto() avresti sicuramente un errore.
    In questo modo invece l'operazione di invocazione del metodo è lecita, lui va a chiamare la funzione allarga() dell'oggetto R che è di tipo rettangolo (risponde alla struttura is-a) ma che di fatto come indirizzo di memoria punta al metodo del quadrato.
    $Pippo... la variabile preferita dall'ingegnere!

  5. #5
    Utente di HTML.it L'avatar di Pastore12
    Registrato dal
    Oct 2008
    Messaggi
    1,051
    Tutto molto bello...ma mi pare in chiara contraddizione con quanto detto nell'esempio precedente
    Non mi ero mai posto un problema del genere!

    Ora, andando esclusivamente per ispirazione, penso che le cose vadano così:
    Quando usi il metodo allarga di un Rettangolo, che è anche un Quadrato, vai comunque a lavorare su una isanza che è un oggetto di tipo Quadrato e quindi ha il suo metodo allarga definito nel suo modo personale.
    Il fatto che sia anche un Rettangolo garantisce che il metodo ci sia, ma non garantisce che quel metodo sia esattamente quello del rettangolo.
    "Ethics are to me something private. Whenever you use it as an argument for why somebody_else should do something, you’re no longer being ethical, you’re just being a sanctimonious dick-head"
    Linus Torvalds

  6. #6
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,320
    Una domanda stupida: chi è quel genio che ti ha detto che Rettangolo estende Quadrato? Da che mondo è mondo è il contrario: un Quadrato è un particolare Rettangolo... non viceversa.

    Un rettangolo è un quadrilatero con 4 angoli retti.
    Un quadrato è un quadrilatero con 4 angoli retti e tutti i lati uguali.

    Forse è l'esempio (brutto, orrendo, sbagliato) che ti confonde le idee...

    Ricorda che la relazione deve sempre essere valida: la classe derivata è sempre un oggetto della classe base. Ora, costruisci un rettangolo 8x2 e chiediti se questo può essere un quadrato. Non funzionerà mai..

    Viceversa, costruisci un quadrato qualunque: questo sarà sempre anche un (particolare) rettangolo.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  7. #7
    Utente di HTML.it
    Registrato dal
    Jun 2004
    Messaggi
    643
    Originariamente inviato da LeleFT
    Una domanda stupida: chi è quel genio che ti ha detto che Rettangolo estende Quadrato? Da che mondo è mondo è il contrario: un Quadrato è un particolare Rettangolo... non viceversa.

    Un rettangolo è un quadrilatero con 4 angoli retti.
    Un quadrato è un quadrilatero con 4 angoli retti e tutti i lati uguali.

    Forse è l'esempio (brutto, orrendo, sbagliato) che ti confonde le idee...


    Ciao.
    Devi aver letto male...c'è chiaramente scritto che un Quadrato è un particolare tipo di Rettangolo avente in piùil vincolo di avere i lati uguali...

    Cmq ho risolto alla fine...

    Sostanzialmente in Java se ho una classe Rettangolo con dei metodi ed una sottoclasse Quadrato con gli stessi metodi (ma ridefiniti) della superclasse Rettangolo più un metodo B() definito solo in Quadrato.

    Se dichiaro R come Rettangolo ma costruisco l'oggetto come Quadrato e se invoco un metodo cmq definito anche in Rettangolo...allora verrà eseguita la versione ridefinita in Quadrato.

    Se invece dichiaro R come Rettangolo, lo costruisco come Quadrato ed invoco il metodo B() definito solo in Quadrato darà errore in fase di compilazione

  8. #8
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,320
    Originariamente inviato da D4rkAng3l
    Devi aver letto male...c'è chiaramente scritto che un Quadrato è un particolare tipo di Rettangolo avente in piùil vincolo di avere i lati uguali...
    Oggi ho una particolare dislessia... ho letto due volte quella frase perchè non mi tornava il concetto e per due volte ho invertito le parti. VVoVe:

    E' lunedì...


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  9. #9
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,320
    Originariamente inviato da D4rkAng3l

    Sostanzialmente in Java se ho una classe Rettangolo con dei metodi ed una sottoclasse Quadrato con gli stessi metodi (ma ridefiniti) della superclasse Rettangolo più un metodo B() definito solo in Quadrato.

    Se dichiaro R come Rettangolo ma costruisco l'oggetto come Quadrato e se invoco un metodo cmq definito anche in Rettangolo...allora verrà eseguita la versione ridefinita in Quadrato.

    Se invece dichiaro R come Rettangolo, lo costruisco come Quadrato ed invoco il metodo B() definito solo in Quadrato darà errore in fase di compilazione
    Esattamente, per una questione molto semplice:

    Dichiarando una variabile come oggetto di un supertipo non significa aver in memoria un oggetto del supertipo, ma solo avere una limitata visibilità sui metodi. Puoi, quindi, utilizzare solo i metodi visibili dal supertipo. Ma il metodo che verrà effettivamente invocato, non dipende dal tipo con cui esso è stato dichiarato, ma dall'effettiva implementazione di quel metodo in memoria (che è sempre quello più vicino all'oggetto reale).


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  10. #10
    Utente di HTML.it
    Registrato dal
    Mar 2002
    Messaggi
    137
    Originariamente inviato da LeleFT
    Esattamente, per una questione molto semplice:

    Dichiarando una variabile come oggetto di un supertipo non significa aver in memoria un oggetto del supertipo, ma solo avere una limitata visibilità sui metodi. Puoi, quindi, utilizzare solo i metodi visibili dal supertipo. Ma il metodo che verrà effettivamente invocato, non dipende dal tipo con cui esso è stato dichiarato, ma dall'effettiva implementazione di quel metodo in memoria (che è sempre quello più vicino all'oggetto reale).


    Ciao.
    mi sono perso.. riformula un po' la faccenda per favore..
    Non è come ho scritto io poco sopra?
    $Pippo... la variabile preferita dall'ingegnere!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.