Visualizzazione dei risultati da 1 a 8 su 8

Discussione: [Java] Polimorfismo

  1. #1

    [Java] Polimorfismo

    Voglio chiedere una cosa semplicissima per chi la sa.

    Mettiamo caso che io abbia una classe Veicoli che è superclasse di Automobile.

    Cosa accade quando scrivo questa istruzione?

    Veicolo A = new Automobile ();
    E che differenza c'è dunque tra l'istruzione appena scritta e queste?

    Veicolo B = new Veicolo ();
    Faccio questa domanda perchè nella prima istruzione, se non sbaglio, non posso chiamare sull'oggetto A una funzione della sottoclasse Automobile.

    E allora che differenza c'è?

  2. #2
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    A parte l'esempio che hai posto, che è puramente didattico, la differenza sta proprio nel fatto che dichiarando un oggetto come tipo "Superclasse" non possono essere invocati su di esso tutti i metodi specifici della sottoclasse, per il semplice fatto che il compilatore non sa a priori di quale sottoclasse sia l'oggetto (ce ne possono essere diversi).

    Forse con un esempio diverso la cosa risulta più chiara:

    Classe: Figura

    Sottoclassi: Triangolo, Rettangolo, Cerchio.

    Ipotizzando che Figura metta a disposizione questi metodi astratti:

    - calcolaPerimetro();
    - calcolaArea();

    ciascuna sottoclasse li implementerà a suo modo:

    Triangolo
    Area: base * altezza / 2;
    Perimetro: lato1 + lato2 + lato3;

    Rettangolo
    Area: base * altezza;
    Perimetro: (base + altezza) * 2;

    Cerchio
    Area: (raggio ^ 2) * PI;
    Perimetro: raggio * 2 * PI;

    Ora vediamo questa situazione:
    codice:
    Figura f1 = new Triangolo();
    Figura f2 = new Rettangolo();
    Figura f3 = new Cerchio();
    Su tutti gli oggetti (f1, f2, f3) io posso invocare i metodi calcolaPerimetro() e calcolaArea():
    codice:
    f1.calcolaArea();
    f2.calcolaArea();
    f3.calcolaArea();
    Ognuno dei quali calcolerà l'area nel modo corretto in base alla "figura reale".

    Ma posso io invocare, ad esempio, il metodo "getRaggio()" (che posso supporre esista nella classe Cerchio) sugli oggetti f1 e f2? Avrebbe senso? E come fa il compilatore a sapere che la chiamata sull'oggetto f1 è errata, mentre su f3 è corretta visto che entrambi gli oggetti sono dichiarati di tipo "Figura"?

    In una situazione come la seguente, quindi, è impossibile richiamare i metodi specifici per ciascuna sottoclasse, proprio perchè il compilatore non può conoscerli in anticipo. E', invece, lecito richiamare uno dei due metodi "calcolaPerimetro()" o "calcolaArea()" perchè sono comuni a tutti gli oggetti di tipo Figura e, di conseguenza, anche a tutti gli oggetti delle sottoclassi.

    La tua prossima domanda sarà: allora a che serve dichiarare un oggetto di tipo "Figura", visto che non posso accedere ai metodi specifici?

    Risposta: non in tutte le situazioni puoi sapere a priori che tipo di Figura stai maneggiando. Esempio:

    codice:
    // Questo metodo fa parte di una classe che non c'entra nulla con le figure
    // ma le usa in modo appropriato
    public double differenzaAree(Figura f1, Figura f2) {
       return f1.calcolaArea() - f2.calcolaArea();
    }
    Il metodo qui sopra è molto generico: calcola la differenza fra le aree di due figure qualsiasi e può essere richiamato in tanti modi:
    codice:
    Rettangolo r = new Rettangolo();
    Triangolo t = new Triangolo();
    Cerchio c = new Cerchio();
    
    System.out.println( differenzaArea(r, r) );
    System.out.println( differenzaArea(r, c) );
    System.out.println( differenzaArea(r, t) );
    System.out.println( differenzaArea(c, c) );
    System.out.println( differenzaArea(c, t) );
    System.out.println( differenzaArea(t, t) );
    ...
    Non importa che tipo di oggetto gli viene passato: lui lavora in modo corretto!


    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

  3. #3
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: [Java] Polimorfismo

    Originariamente inviato da ragnonerodocet
    E che differenza c'è dunque tra l'istruzione appena scritta e queste?
    La differenza è solo nell'oggetto realmente istanziato. La variabile però è di tipo Veicolo in entrambi i casi, quindi si potranno invocare solo metodi noti alla classe Veicolo. Per dirla in un altro modo, è il tipo del reference che determina quali metodi sono invocabili mentre è l'oggetto realmente istanziato che determina la implementazione da eseguire.

    Originariamente inviato da ragnonerodocet
    Faccio questa domanda perchè nella prima istruzione, se non sbaglio, non posso chiamare sull'oggetto A una funzione della sottoclasse Automobile.
    Esatto, puoi invocare solo metodi noti alla classe Veicolo.

    Originariamente inviato da ragnonerodocet
    E allora che differenza c'è?
    Ok, esempio:

    codice:
    class Veicolo {
        public void unMetodo () { System.out.println ("A"); }
    }
    
    class Automobile extends Veicolo {
        public void unMetodo () { System.out.println ("B"); }
        public void altroMetodo () { System.out.println ("C"); }
    }
    
    
    Veicolo v1 = new Veicolo ();
    Veicolo v2 = new Automobile ();
    Poi:

    v1.unMetodo();

    Questo è ok, stampa "A" perché l'oggetto è un Veicolo.

    v2.unMetodo();

    Questo è ok, stampa "B" perché l'oggetto è un Automobile, che fa l'override del metodo. Il compilatore stabilisce che la invocazione è ok solamente perché il reference è Veicolo ed ha un metodo unMetodo(). Ma la implementazione è scelta a runtime perché l'oggetto è un Automobile e il metodo è ridefinito.


    v1.altroMetodo();
    v2.altroMetodo();

    Sono entrambi sbagliati, il compilatore dà errore. Non c'è un metodo altroMetodo() in Veicolo. Anche se il secondo oggetto realmente istanziato è un Automobile, comunque il reference è di tipo Veicolo e il compilatore non puoi trovare alcuna signature di altroMetodo().
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  4. #4
    Ho seguito alla perfezione il Suo esempio e La ringrazio per le informazioni che mi ha dato, permettendomi di comprendere quello che prima risultava oscuro.

    Ho però un'altra domanda inerente al uo esempio.

    Se nel suo caso scrivo questo:

    Figura a = new Cerchio ();
    a.getRaggio();
    il compilatore dà errore, perchè il metodo getRaggio non è presente nella superclasse Figura.

    Allora faccio due domande.

    1- Prendendo queste due linee di codice, Lei scrive "In una situazione come la seguente, quindi, è impossibile richiamare i metodi specifici per ciascuna sottoclasse, proprio perchè il compilatore non può conoscerli in anticipo". Perchè no? Eppure scrivo "new Cerchio()"...

    2- Se comunque volessi calcolare il raggio di a, mediante il metodo della classe Cerchio chiamata getRaggio, dovrei fare un cast?

  5. #5
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da ragnonerodocet
    1- Prendendo queste due linee di codice, Lei scrive "In una situazione come la seguente, quindi, è impossibile richiamare i metodi specifici per ciascuna sottoclasse, proprio perchè il compilatore non può conoscerli in anticipo". Perchè no? Eppure scrivo "new Cerchio()"...
    Ma la variabile 'a' è di tipo Figura .... è quello che conta!! Figura ha un metodo getRaggio()??? No, allora la invocazione non è possibile.

    È il tipo del reference che determina quali metodi sono invocabili.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  6. #6
    Grazie a tutti per la spiegazione. Adesso mi risulta tutto più chiaro.

    Ultimissima cosa...

    Se allora scrivo così:

    Figura a = new Cerchio();

    come faccio sull'oggetto "a" a richiamare il metodo getRaggio?

    Può essere così?

    (Cerchio)a.getRaggio();

    cioè con un cast?

    E dopo questo cast, cambia il reference di "a" e dunque posso chiamare metodi specifici di sottoclasse senza fare cast?

    Poi adesso me ne viene un'altra...

    public void differenzaAree(Figura f1, Figura f2) {
    Posso passare a questa funzione due oggetti di questo tipo

    Cerchio a = new Cerchio();
    Triangolo b = new Triangolo();

    Credo di si, essendo appartenenti anche implicitamente alla classe Figura...

  7. #7
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Originariamente inviato da ragnonerodocet
    Grazie a tutti per la spiegazione. Adesso mi risulta tutto più chiaro.

    Ultimissima cosa...

    Se allora scrivo così:

    Figura a = new Cerchio();

    come faccio sull'oggetto "a" a richiamare il metodo getRaggio?

    Può essere così?

    (Cerchio)a.getRaggio();

    cioè con un cast?
    Esattamente. O meglio:
    codice:
    ((Cerchio) a).getRaggio();
    E dopo questo cast, cambia il reference di "a" e dunque posso chiamare metodi specifici di sottoclasse senza fare cast?
    No: il cast è un modo, diciamo, temporaneo di vedere una variabile: nel momento in cui viene effettuata l'operazione (cioè solo al momento del cast) quella variabile viene vista come una variabile di tipo diverso, ma in tutto il resto del programma essa è e resterà sempre di tipo "Figura".

    Poi adesso me ne viene un'altra...



    Posso passare a questa funzione due oggetti di questo tipo

    Cerchio a = new Cerchio();
    Triangolo b = new Triangolo();

    Credo di si, essendo appartenenti anche implicitamente alla classe Figura...
    E' esattamente l'esempio che ho fatto...

    PS: dammi del TU, non del Lei...


    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

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da ragnonerodocet
    Può essere così?

    (Cerchio)a.getRaggio();

    cioè con un cast?
    Sì il cast cambia il reference. Comunque attenzione, perché è da fare così:

    ((Cerchio)a).getRaggio();

    Le parentesi che ho messo non sono superflue ... l'operatore '.' (accesso a un membro) ha priorità maggiore del cast, quindi le parentesi ci vogliono!

    Originariamente inviato da ragnonerodocet
    E dopo questo cast, cambia il reference di "a" e dunque posso chiamare metodi specifici di sottoclasse senza fare cast?
    No, cambia solo in quel preciso punto nella invocazione. Il tipo della variabile non è modificabile.

    Semmai puoi fare:

    Cerchio c = (Cerchio) a;

    A questo punto da lì in poi hai un reference a Cerchio.

    Indipendentemente da come lo fai, quello è un "down-cast" e ha delle implicazioni. Un down-cast prevede un controllo in fase di runtime. La JVM va a verificare se l'oggetto è realmente un Cerchio. Se non lo è lancia ClassCastException.

    Originariamente inviato da ragnonerodocet
    Poi adesso me ne viene un'altra...

    public void differenzaAree(Figura f1, Figura f2) {

    Posso passare a questa funzione due oggetti di questo tipo

    Cerchio a = new Cerchio();
    Triangolo b = new Triangolo();

    Credo di si, essendo appartenenti anche implicitamente alla classe Figura...
    Sì, entrambi sono anche di tipo Figura, visto che la estendono.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

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 © 2026 vBulletin Solutions, Inc. All rights reserved.