Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 18

Discussione: Parametri covarianti

  1. #1
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315

    Parametri covarianti

    Sto studiando i tipi generici e mi sono bloccato nella comprensione di un esempio.
    Il manuale cita questo esempio:
    codice:
    interface Cibo
    {
         String getColore();
    }
    codice:
    interface Animale
    {
        void mangia(Cibo cibo) throws CiboException
    }
    codice:
    public class Erba implements Cibo
    {
        public String getColore()
        {
              return "verde";
        }
    }
    codice:
    public class Carnivoro implements Animale
    {
        public void mangia(Cibo cibo) throws CiboException
        {
             if(!(cibo instanceof Erbivoro)
             {
                   throw new CiboException("Un carnivoro deve mangiare " + "erbivori");
             }      
        }
    }
    codice:
    public class Erbivoro implements Cibo, Animale
    {
        public void mangia(Cibo cibo) throws CiboException
        {
             if(!(cibo instanceof Erba)
             {
                   throw new CiboException("Un erbivoro deve mangiare " + "erba");
             }
        }
        
        public String getColore()
        {
              ...
        }
    }
    codice:
    public class CiboException extends Exception
    {
        public CiboException(String msg)
        {
              super(msg);
        }
    }
    codice:
    public class TestAnimali
    {
        public static void main(String args[])
        { 
             try
             {
                   Animale tigre = new Carnivoro();
                   Cibo erba = new Erba();
                   tigre.mangia(erba);
             }
             catch(CiboException exc)
             {
                   exc.printStackTrace();
             }
        }
    }


    Questa soluzione è valida però il manuale, per evitare la gestione delle eccezioni, ne propone un'altra utilizzando i tipi parametro:
    codice:
    interface Cibo
    {
         String getColore();
    }
    codice:
    interface Animale<C extends Cibo>
    {
        void mangia(C cibo)
    }
    codice:
    public class Erba implements Cibo
    {
        public String getColore()
        {
              return "verde";
        }
    }
    codice:
    public class Carnivoro implements Animale<Erbivoro>
    {
        public void mangia(Erbivoro erbivoro)
        {
             // un carnivoro potrebbe mangiare erbivori
        }
    }
    codice:
    public class Erbivoro<E extends Erba> implements Cibo, Animale<E>
    {
        public void mangia(E erba)
        {
              // un erbivoro mangia erba
        }
        
        public String getColore()
        {
              ...
        }
    }
    codice:
    public class TestAnimali
    {
        public static void main(String args[])
        { 
             Animale<Erbivoro> tigre = new Carnivoro<Erbivoro>();
             Erbivoro<Erba> erbivoro = new Erba<Erba>();
             tigre.mangia(erbivoro);
        } 
    }

    Il problema è che non ho capito nell'ultima soluzione come ha utilizzato i tipi parametro, mi sfuggono proprio i vari passaggi nel codice.
    Potete aiutarmi nella comprensione?

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da newutente Visualizza il messaggio
    Il problema è che non ho capito nell'ultima soluzione come ha utilizzato i tipi parametro
    Mah ... il codice è comunque sbagliato, almeno per come l'hai postato qui.
    Se Carnivoro è definito come:

    public class Carnivoro implements Animale<Erbivoro>

    allora NON puoi fare new Carnivoro<Erbivoro>()

    Il punto è che per poter fare una istanziazione del tipo Carnivoro<UnTipoReale> la classe Carnivoro dovrebbe avere una type variable e .... non ce l'ha.

    Idem per Erba.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Mah ... il codice è comunque sbagliato, almeno per come l'hai postato qui.
    Effettivamente avevo sbagliato la trascrizione però solo della seconda riga.
    Questo è il main così come è scritto sul manuale.

    codice:
    public class TestAnimali
    {
        public static void main(String args[])
        { 
             Animale<Erbivoro> tigre = new Carnivoro<Erbivoro>();
             Erbivoro<Erba> erbivoro = new Erbivoro<Erba>();
             tigre.mangia(erbivoro);
        } 
    }

    Quote Originariamente inviata da andbin Visualizza il messaggio
    Se Carnivoro è definito come:

    public class Carnivoro implements Animale<Erbivoro>

    allora NON puoi fare new Carnivoro<Erbivoro>()

    Il punto è che per poter fare una istanziazione del tipo Carnivoro<UnTipoReale> la classe Carnivoro dovrebbe avere una type variable e .... non ce l'ha.

    Idem per Erba.
    Quindi la dichiarazione della classe dovrebbe essere così:

    public class Carnivoro<Erbivoro> implements Animale<Erbivoro>

    Giusto?

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da newutente Visualizza il messaggio
    Questo è il main così come è scritto sul manuale.
    Resta comunque sbagliata (la prima istanziazione) se la dichiarazione di Carnivoro resta quella detta prima, ovvero:

    public class Carnivoro implements Animale<Erbivoro>


    Quote Originariamente inviata da newutente Visualizza il messaggio
    Quindi la dichiarazione della classe dovrebbe essere così:

    public class Carnivoro<Erbivoro> implements Animale<Erbivoro>

    Giusto?
    No, con la dichiarazione di Carnivoro come sopra, basta semplicemente:

    new Carnivoro()

    senza alcuna parametrizzazione. Perché Carnivoro è-un Animale<Erbivoro>, è già parametrizzato in questo senso!


    P.S. suggerimento: se hai un po' di dimestichezza con l'inglese, se mi permetti, ti suggerisco di leggere il capitolo 8 sui Generics del libro "Learning Java 3rd Edition", che trovi su google books:

    http://books.google.it/books?id=fu5H...page&q&f=false

    Il capitolo lo puoi leggere praticamente per intero, è solo oscurata l'ultima pagina del capitolo che contiene solamente le "conclusioni". Ti assicuro che è molto utile (e lo è stato per me).
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    Ho compreso un po' meglio quell'esempio però avrei una domanda. In realtà si ricollega al discorso del polimorfismo per dati fatto nell'altra discussione ma visto che parliamo di questo specifico esempio la faccio qui.

    Abbiamo detto che la classe di test corretta è questa:
    codice:
    public class TestAnimali
    {
        public static void main(String args[])
        { 
             Animale<Erbivoro> tigre = new Carnivoro();
             Erbivoro<Erba> erbivoro = new Erbivoro<Erba>();
             tigre.mangia(erbivoro);
        } 
    }
    Nella prima riga del main viene dichiarata una variabile reference di tipo Animale a cui poi viene assegnato l'oggetto Carnivoro istanziato.
    Questa riga mette in evidenza il polimorfismo e viene invocato, nella terza riga, il metodo mangia dell'oggetto istanziato (e non quello di Animale).
    La mia domanda è: se è vero quello che ho appena detto perchè nella seconda riga viene creata una variabile reference di tipo Erbivoro e non di tipo Animale? Provo a rispondere. Perchè in quel caso la variabile reference serve solo per essere passata in input al metodo mangia?

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da newutente Visualizza il messaggio
    La mia domanda è: se è vero quello che ho appena detto perchè nella seconda riga viene creata una variabile reference di tipo Erbivoro e non di tipo Animale? Provo a rispondere. Perchè in quel caso la variabile reference serve solo per essere passata in input al metodo mangia?
    Animale è:

    interface Animale<C extends Cibo>

    La variabile tigre è Animale<Erbivoro> e con questa parametrizzazione concreta, il C viene fissato a Erbivoro, quindi da un oggetto che è visto come un Animale<Erbivoro> ci si aspetta che abbia un mangia(Erbivoro).
    Difatti Carnivoro che è proprio Animale<Erbivoro> ridefinisce concretamente il mangia(Erbivoro).

    Invocando tigre.mangia( ..... ) puoi passare qualunque cosa che è-un Erbivoro. Non puoi passare una variabile di tipo Animale<QualunqueCibo> perché Erbivoro<QualunqueCibo> è-un Animale<QualunqueCibo> ..... ma il contrario no!


    P.S. lo scenario che è descritto con quelle classi/interfacce di esempio ammetto che è un pochino contorto. Se vuoi esempi più lineari con i generics, te ne posso anche fare!
    Ultima modifica di andbin; 26-11-2014 a 15:23
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    Quote Originariamente inviata da andbin Visualizza il messaggio
    P.S. lo scenario che è descritto con quelle classi/interfacce di esempio ammetto che è un pochino contorto. Se vuoi esempi più lineari con i generics, te ne posso anche fare!
    se non ti è di troppo disturbo te ne sarei grato.
    anche perchè concettualmente direi che mi sono chiari questi concetti ma ho bisogno forse di esempi più lineari per fissarli meglio.
    Ultima modifica di newutente; 26-11-2014 a 15:39

  8. #8
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    se appena hai un attimo mi fai qualche esempio più lineare riesco a fissare meglio i concetti. senza fretta ovviamente.

  9. #9
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Non so se può esserti utile (e se è quanto ti aspetti) ma vedi questo. Data una interfaccia generica:

    codice:
    public interface ObjectFilter<T> {
        boolean accept(T t);
    }

    codice:
    import java.util.ArrayList;
    import java.util.List;
    
    public class Test {
        public static void main(String[] args) {
            List<Object> oggetti = new ArrayList<Object>();
            List<Integer> interi = new ArrayList<Integer>();
    
            interi.add(14);
            interi.add(34);
            interi.add(25);
            interi.add(9);
    
            ObjectFilter<Number> numFilter = new ObjectFilter<Number>() {
                public boolean accept(Number num) {
                    return num.doubleValue() < 20;
                }
            };
    
            filtra(interi, oggetti, numFilter);
    
            System.out.println(oggetti);
        }
    
        public static <T> void filtra(List<? extends T> src, List<? super T> dst, ObjectFilter<? super T> filter) {
            for (T t : src) {
                if (filter.accept(t)) {
                    dst.add(t);
                }
            }
        }
    }

    Ti è chiaro perché ho usato i bound in quel modo in filtra?
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  10. #10
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    Sinceramente no. Cioè ho capito cosa fa il programma però non capisco perchè hai utilizzato i bound in quel modo.

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.