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

Discussione: classi anonime

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

    classi anonime

    Sto studiando le classi anonime e in tutta sincerità ho capito poco.
    Sul manuale c'è un esempio che dovrebbe permettere di comprendere bene il funzionamento delle classi anonime.
    L'esempio è il seguente:
    codice:
    public class Film {
        private String nome;
        private String genere;
        private int mediaRecensioni;
    
        public Film (String nome, String genere, int mediaRecensioni) {
            this.nome = nome;
            this.genere = genere;
            this.mediaRecensioni = mediaRecensioni;
        }
    
        // metodi set e get omessi
         
        public String toString(){
            return getNome();
        }
    }
    codice:
    public class Videoteca {
        private Film[] films;
    
        public Videoteca () {
            films = new Film[10];
            caricaFilms();
        }
        public void setFilms(Film[] films) {
            this.films = films;
        }
    
        public Film[] getFilms() {
            return films;
        }
    
        public Film[] getFilmDiFantascienza() {
            Film [] filmDiFantascienza = new Film[10];
            for (int i = 0, j= 0; i< 10;i++) {
                if ("Fantascienza".equals(films[i].getGenere())) {
                    filmDiFantascienza[j] = films[i];
                    j++;
                }
            }
            return filmDiFantascienza;
        }
    
        public Film[] getBeiFilm() {
            Film [] beiFilms = new Film[10];
            for (int i = 0, j= 0; i< 10;i++) {
                if (films[i].getMediaRecensioni() >3) {
                    beiFilms[j] = films[i];
                    j++;
                }
            }
            return beiFilms;
        }
    
        private void caricaFilms() {
            
        // caricamento film 
    
        }
    }
    codice:
    public class TestVideoteca {
        public static void main(String args[]) {
            Videoteca videoteca = new Videoteca();
            
        System.out.println("\nFilm di Fantascienza:");
            Film[] filmDiFantascienza = videoteca.getFilmDiFantascienza();
        for(Film film : filmDiFantascienza)
            {
            if(film != null)
            {
                System.out.println(film);
            }    
        }
    
        // omesso test bei film
    }
    A Questo punto il manuale dice che la soluzione migliore consiste nell'utilizzo delle classi anonime:

    codice:
    public interface FiltroFilm
    {
        boolean filtra(Film film);
    }
    codice:
    public class Videoteca {
        private Film[] films;
    
        public Videoteca () {
            films = new Film[10];
            caricaFilms();
        }
        public void setFilms(Film[] films) {
            this.films = films;
        }
    
        public Film[] getFilms() {
            return films;
        }
    
        public Film[] getFilmFiltrati(FiltroFilm filtroFilm) {
            Film [] filmFiltrati = new Film[10];
            for (int i = 0, j= 0; i< 10;i++) {
                if (filtroFilm.filtra(films[i])) {
                    filmFiltrati[j] = films[i];
                    j++;
                }
            }
            return filmFiltrati;
        }        
    
        private void caricaFilms() {
            
        // caricamento film 
    
        }
    }
    codice:
    public class TestVideoteca {
        public static void main(String args[]) {
              Videoteca videoteca = new Videoteca();
           
          System.out.println("\nFilm di Fantascienza:");
              Film[] filmDiFantascienza = videoteca.getFilmFiltrati(new FiltroFilm() {
                    public boolean filtra(Film film) {
                    return"Fantascienza".equals(film.getGenere());
                  }
              } );
              stampaFilm(filmDiFantascienza);      
       
    
              System.out.println("Bei Film:");
              Film[] beiFilms =   videoteca.getFilmFiltrati(new FiltroFilm() {
                    public boolean filtra(Film film) {
                    return film.getMediaRecensioni() >3;
                    }
              } );
          stampaFilm(beiFilms);
        
           
          private static void stampaFilm(Film [] films) {
              for (Film film: films) {
                    if (film != null) {
                            System.out.println(film);
                    }
              }
               
    }

    Io di questo esempio ho capito ben poco, cioè ho capito l'utilizzo delle classi anonime ma non riesco a comprendere questo specifico caso.
    Mi potete aiutare 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
    codice:
              Film[] filmDiFantascienza = videoteca.getFilmFiltrati(new FiltroFilm() {
                    public boolean filtra(Film film) {
                    return"Fantascienza".equals(film.getGenere());
                  }
              } );
    codice:
              Film[] beiFilms =   videoteca.getFilmFiltrati(new FiltroFilm() {
                    public boolean filtra(Film film) {
                    return film.getMediaRecensioni() >3;
                    }
              } );
    Le classi anonime nel codice sono due, sono quei new FiltroFilm() { .... } riportati qui sopra.

    Una classe anonima è una classe in cui la definizione e la istanziazione praticamente coincidono, sono cioè nello stesso punto. E il termine "anonima" riguarda il fatto che la classe non ha un nome nel sorgente. Nel bytecode generato un nome ovviamente ce l'ha ma è generato dal compilatore e non è noto a priori dal programmatore (in realtà si sa come il compilatore, perlomeno quello Sun/Oracle, genera questi nomi).

    Una classe anonima può fare solo una di queste cose: estendere una classe oppure implementare una (1) interfaccia. Mai entrambe le cose.

    Potrei andare avanti a spiegare ma dovrei dirne parecchie di cose ..... piuttosto, quali sono precisamente i tuoi dubbi?
    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
    Non riesco a capire questi pezzi di codice:
    codice:
    public interface FiltroFilm
    {
        boolean filtra(Film film);
    }
    Ok, una classe anonima può o estendere una classe o implementare una interfaccia. In questo caso è evidente che deve implementare una interfaccia, ma perchè si sceglie di implementare una interfaccia piuttosto che usare una classe ed estenderla?

    codice:
    public Film[] getFilmFiltrati(FiltroFilm filtroFilm) {
            Film [] filmFiltrati = new Film[10];
            for (int i = 0, j= 0; i< 10;i++) {
                if (filtroFilm.filtra(films[i])) {
                    filmFiltrati[j] = films[i];
                    j++;
                }
            }
            return filmFiltrati;
    }
    In questo caso non capisco cosa fa questo metodo. Dovrebbe restituire i film filtrati, ma in base a che criterio?

    codice:
    Film[] filmDiFantascienza = videoteca.getFilmFiltrati(new FiltroFilm() {
                    public boolean filtra(Film film) {
                    return"Fantascienza".equals(film.getGenere());
                    }
              } );
    codice:
    Film[] beiFilms =  videoteca.getFilmFiltrati(new FiltroFilm() {
                    public boolean filtra(Film film) {
                    return film.getMediaRecensioni() >3;
                    }
              } );
    I due pezzi di codice di sopra invece sono la parte principale del dubbio perchè rappresentano appunto le classi anonime.
    Ho capito che la sintassi deve essere del tipo:
    codice:
    FiltroFilm filtro = new FiltroFilm() {
                 public boolean filtra(Film film)
                 {
                    ...
                 }
             };
    e che volendo si può passare questa classe anonima come input ad un metodo (come accade con getFilmFiltrati).
    Quello che però non capisco è cosa realmente accade in quelle righe di codice, in modo particolare il metodo filtra restituisce un booleano. E allora cosa fa quel codice? Passa un booleano al metodo getFilmFiltrati?
    Insomma mi sfugge la logica di questi pezzi di codice.

  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
    Non riesco a capire questi pezzi di codice:
    [...]
    ma perchè si sceglie di implementare una interfaccia piuttosto che usare una classe ed estenderla?
    FiltroFilm è una normalissima interfaccia che definisce un "contratto" di filtro (per questo, è meglio che sia una interfaccia ... non una classe) del tipo "qualcuno ti passa un oggetto Film, digli se true o false". Poi si potrebbe discutere sul senso del boolean, cosa significano true e false. In linea di massima e sensatamente si può pensare: true = il film è ok (insomma, lo accetto).

    Quote Originariamente inviata da newutente Visualizza il messaggio
    In questo caso non capisco cosa fa questo metodo. Dovrebbe restituire i film filtrati
    Se noti, prima passa il Film (films[i]) a filtra che è implementato nell'oggetto passato al metodo getFilmFiltrati. Poi se filtra restituisce true, allora il Film lo mette in un elemento dell'array.
    Insomma, qui è evidente che "true" significa che il Film è accettato, altrimenti viene scartato.

    Quote Originariamente inviata da newutente Visualizza il messaggio
    ma in base a che criterio?
    Questi, chiaramente differenti per ottenere liste differenti:

    codice:
    Film[] filmDiFantascienza = videoteca.getFilmFiltrati(new FiltroFilm() {
                    public boolean filtra(Film film) {
                    return"Fantascienza".equals(film.getGenere());  // <-------- QUESTO criterio
                    }
              } );
    codice:
    Film[] beiFilms =  videoteca.getFilmFiltrati(new FiltroFilm() {
                    public boolean filtra(Film film) {
                    return film.getMediaRecensioni() >3;  // <-------- QUESTO criterio
                    }
              } );
    Quote Originariamente inviata da newutente Visualizza il messaggio
    Quello che però non capisco è cosa realmente accade in quelle righe di codice, in modo particolare il metodo filtra restituisce un booleano. E allora cosa fa quel codice? Passa un booleano al metodo getFilmFiltrati?
    getFilmFiltrati riceve un oggetto che "vede" solo come tipo FiltroFilm (la interfaccia). A getFilmFiltrati NON importa dove è implementata la interfaccia, se in una classe top-level, se in una inner-class "regular" oppure "anonymous" (anonima) o altro.

    A getFilmFiltrati interessa solo che l'oggetto è un FiltroFilm, quindi di sicuro ha quel metodo filtra. Quindi il metodo getFilmFiltrati passerà tutti i Film presenti, uno per volta, al metodo filtra, ovvero invoca filtra sull'oggetto FiltroFilm. filtra restituisce un boolean, in base a questo, getFilmFiltrati si comporta di conseguenza.
    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
    Quote Originariamente inviata da andbin Visualizza il messaggio
    FiltroFilm è una normalissima interfaccia che definisce un "contratto" di filtro
    Ti riferisci al fatto che definendo una interfaccia si è in qualche modo costretti poi a implementare i suoi metodi?

    Quote Originariamente inviata da andbin Visualizza il messaggio
    A getFilmFiltrati NON importa dove è implementata la interfaccia, se in una classe top-level, se in una inner-class "regular" oppure "anonymous" (anonima) o altro.
    Ah ecco, quindi diciamo che questo esempio mostra che volendo è possibile implementare i metodi di una interfaccia anche tramite una classe anonima. Giusto?

  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
    Ti riferisci al fatto che definendo una interfaccia si è in qualche modo costretti poi a implementare i suoi metodi?
    Anche facendo una classe astratta con metodo astratto avresti lo stesso obbligo (ovviamente in una classe concreta):

    codice:
    public abstract class FiltroFilm {
        public abstract boolean filtra(Film film);
    }

    A livello di "contratto" e di obblighi non ci sono differenze: in una classe concreta che estende FiltroFilm devi implementare filtra. La dichiarazione-istanziazione con una classe anonima è esattamente la stessa con FiltroFilm come interfaccia o come classe astratta.
    Il punto è che una interfaccia la puoi implementare in qualunque classe. Una classe astratta .... no, non è detto (una classe può già estendere altro).

    Quote Originariamente inviata da newutente Visualizza il messaggio
    Ah ecco, quindi diciamo che questo esempio mostra che volendo è possibile implementare i metodi di una interfaccia anche tramite una classe anonima. Giusto?
    Sì, se quel comportamento non deve essere riutilizzabile altrove.
    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
    Il punto è che una interfaccia la puoi implementare in qualunque classe. Una classe astratta .... no, non è detto (una classe può già estendere altro).
    cioè una interfaccia è sufficiente che la implementi per implementare quel metodo, una classe astratta invece la devi comunque estendere tramite un'altra classe e quindi devi comunque creare una relazione di ereditarietà. Giusto?


    p.s. vado un attimo off topic perchè vorrei segnalarti il mio ultimo post ( http://forum.html.it/forum/showthrea...readid=2918433 ) che forse è sfuggito.

  8. #8
    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
    cioè una interfaccia è sufficiente che la implementi per implementare quel metodo, una classe astratta invece la devi comunque estendere tramite un'altra classe e quindi devi comunque creare una relazione di ereditarietà. Giusto?
    Ma anche implementando una interfaccia si ha una relazione di "ereditarietà".

    Che FiltroFilm sia interfaccia:

    public class MyCustomFiltroFilm implements FiltroFilm { .... }

    Oppure che FiltroFilm sia classe astratta (con filtra abstract):

    public class MyCustomFiltroFilm extends FiltroFilm { .... }

    In entrambi i casi FiltroFilm è comunque un "super" tipo di MyCustomFiltroFilm. E per quanto riguarda MyCustomFiltroFilm, gli obblighi sono gli stessi: se non è astratta (come definizione sopra), allora deve implementare quel metodo filtra.


    Quote Originariamente inviata da newutente Visualizza il messaggio
    p.s. vado un attimo off topic perchè vorrei segnalarti il mio ultimo post ( http://forum.html.it/forum/showthrea...readid=2918433 ) che forse è sfuggito.
    Vedo di risponderti appena posso.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  9. #9
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    Il concetto mi è chiaro, volevo però fare una considerazione.
    Da quello che ho capito le classi anonime vanno dichiarate all'interno del corpo di un metodo o passate come parametro ad un metodo e trovano l'utilizzo migliore quando vogliamo fare in una classe override di un metodo di un'altra classe/interfaccia/classe astratta.
    Per semplicità vi posto nuovamente i 2 esempi più concreti dove si notano i due utilizzi:

    ESEMPIO 1
    codice:
    public class Outer4 
    {
        
        private String messaggio = "Nella classe ";
    
        
        
        public void metodoConClasse(final int a) 
        {
            
            ClasseEsistente ce = new ClasseEsistente()    
            {
                
                @Override
    
                        public void metodo() 
                {
        
                        System.out.println(messaggio+"anonima numero "+ a);
                
                }
            
            };
            
            ce.metodo();
        
        }
    
    }
    
    public class ClasseEsistente
    {
        public void metodo()
        {
            System.out.println("Nella classe esistente");
        }
    }

    ESEMPIO 2
    codice:
    public class TestPersona {
    
        public static void main(String args[])
            {
            System.out.println(new Persona("Arjen","Lucassen","03/04/1960","Compositore","Olanda")
                    {
                         @Override
                         public String toString()
                         {
                                                 ...
                         }
                    } );
        }    
    }
    
    
    public class Persona 
    {
        ...
    
        @Override
        public String toString() {
            return "Persona{" + "nome=" + nome + ", cognome=" + cognome + '}';
        }
    }


    In entrambi i casi è come se andassimo ad istanziare un oggetto di una classe già esistente e lo facciamo per avere accesso ad un particolare metodo su cui vogliamo appunto fare l'override.
    E' corretto? Se si, allora la mia domanda è: non avremmo ottenuto lo stesso risultato estendendo la classe già esistente piuttosto che utilizzando una classe anonima? Avremmo lo stesso avuto l'accesso al metodo su cui fare l'override.

  10. #10
    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
    Da quello che ho capito le classi anonime vanno dichiarate all'interno del corpo di un metodo o passate come parametro ad un metodo
    Una anonymous inner class può essere usata dovunque si possa assegnare un reference. Quindi: assegnamenti a variabili (locali, di istanza, di classe), argomenti di costruttori/metodi.

    Quote Originariamente inviata da newutente Visualizza il messaggio
    e trovano l'utilizzo migliore quando vogliamo fare in una classe override di un metodo di un'altra classe/interfaccia/classe astratta.
    L'uso principale è per l'override "al volo" di uno o pochi metodi quando non c'è bisogno di particolare riutilizzo di quella implementazione.
    E si parla solo di override, perché siccome la classe è "anonima", il nome non lo sai e se mettessi dei metodi "nuovi", in più rispetto al super-tipo che estendi/implementi, non sapendo il nome classe, non potresti usarli! (a parte istanziare e invocare subito al volo 1 metodo).

    Quote Originariamente inviata da newutente Visualizza il messaggio
    non avremmo ottenuto lo stesso risultato estendendo la classe già esistente piuttosto che utilizzando una classe anonima? Avremmo lo stesso avuto l'accesso al metodo su cui fare l'override.
    Ai fini del override, non c'è differenza tra l'usare una classe anonima e una classe "regolare" (top-level o inner). Conta più che altro la brevità o meno e il (più o meno) interesse per il riutilizzo.

    Le differenze tecniche ovviamente ci sono: in una classe anonima non puoi definire tu un costruttore. In una classe regolare, sì ovviamente. Poi ad esempio in una classe anonima non puoi definire membri static (al massimo li puoi ereditare) per lo stesso motivo detto sopra: non sapendo il nome della classe, non potresti usarli. In una classe regolare puoi definire membri static.
    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 © 2025 vBulletin Solutions, Inc. All rights reserved.