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

Discussione: hashSet

  1. #1

    hashSet

    Ciao,
    ho un problema che credo sia banale ma io non riesco ad uscirne fuori.
    Ho una classe Studente:
    Codice PHP:
    public class Studente {

        
    String matricola;
        
    String nome;
        
    String cognome;
        
    String citta;

        
    // Costruttore
        
    public Studente(String unaMatricolaString unNomeString unCognomeString unaCitta){
            
    this.matricola=unaMatricola;
            
    this.nome=unNome;
            
    this.cognome=unCognome;
            
    this.citta=unaCitta;
        }
        
        public 
    String getNome () {
            return 
    nome;
        }

        public 
    void setNome (String val) {
            
    this.nome val;
        }

        public 
    String getCognome () {
            return 
    cognome;
        }

        public 
    void setCognome (String val) {
            
    this.cognome val;
        }

        public 
    String getCitta () {
            return 
    citta;
        }

        public 
    void setCitta (String val) {
            
    this.citta val;
        }
        public 
    String getMatricola () {
            return 
    matricola;
        }

        public 
    void setMatricola (String val) {
            
    this.matricola val;
        }

        
        @
    Override
        
    public String toString(){
            return 
    "STAMPA INFO STUDENTE: "+matricola+" - "+nome+" - "+cognome+" - "+citta;
        }   

    In un metodo di un altra classe ho un Set di oggetti di tipo Studente (praticamente usando la classe hashSet considerando che un Set non ammette doblicati):
    [PHP]
    HashSet<Studente> hashStudenti = new HashSet<Studente>();
    [PHP]
    Aggiungendo per due volte un studente (lo stesso studente), lo hashStudenti.size() diventa due piuttosto che uno come dovrei aspettarmelo visto che non si ammetono dublicati. Come mai? Quando è che due oggetti di tipo Studente sono uguali per hashSet?

    Grazie in anticipo,
    Gentjan

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

    Re: hashSet

    Originariamente inviato da coocooche
    Aggiungendo per due volte un studente (lo stesso studente), lo hashStudenti.size() diventa due piuttosto che uno come dovrei aspettarmelo visto che non si ammetono dublicati.
    Il concetto di "non ammette duplicati" per i "set" e anche per le chiavi delle "map" (insomma, tutte le collezioni che sono basate su una "hash table" interna) è subordinato al fatto di avere nella classe degli oggetti una implementazione corretta ed appropriata di equals() e hashCode() tale da rispettare il contratto tra questi due metodi.

    Metodi che nella tua classe Studente non hai implementato, restano quelli implementati in Object che si basano solo sulla identità degli oggetti.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Sorry, ho individuato e risolto già il problema ma mi hai preceduto con la risposta
    Ho imparato la lezione che per ogni classe creata bisogna (forse sempre) creare toString(), equals() e hashCode().
    Grazie mille cmq!

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da coocooche
    ho individuato e risolto già il problema
    Bene, se vuoi posta equals()/hashCode() che vediamo se sono ok.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Codice PHP:
    public boolean equals(Object o){
          
    Studente s;
          if(
    o==null){return false;}
          
    s=(Studenteo;
          return (
    this.nome.equals(s.nome)) && (this.cognome.equals(s.cognome))
                 && (
    this.citta.equals(s.citta)) && (this.matricola.equals(s.matricola));
        }

        public 
    int hashCode() {
            
    int hash 7;
            
    hash 19 hash + (this.matricola != null this.matricola.hashCode() : 0);
            
    hash 19 hash + (this.nome != null this.nome.hashCode() : 0);
            
    hash 19 hash + (this.cognome != null this.cognome.hashCode() : 0);
            
    hash 19 hash + (this.citta != null this.citta.hashCode() : 0);
            return 
    hash;
        } 
    Ora il codice funziona perfettamente ma mi piacerebbe sapere come generare il metodo hashCode() senza l'aiuto del editor (l'ho dovuto generare tramite NetBeans)...

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da coocooche
    Codice PHP:
    public boolean equals(Object o){
          
    Studente s;
          if(
    o==null){return false;}
          
    s=(Studenteo;
          return (
    this.nome.equals(s.nome)) && (this.cognome.equals(s.cognome))
                 && (
    this.citta.equals(s.citta)) && (this.matricola.equals(s.matricola));
        } 
    Per equals() generalmente si fa un test con l'operatore instanceof e solo se hai appurato che l'oggetto è un Studente puoi fare il cast. equals() non deve mai poter lanciare un ClassCastException.

    Se si vuole si può anche gestire a priori un caso particolare: se l'oggetto passato è == al this si può ritornare subito un bel true. È solo una ottimizzazione.

    Originariamente inviato da coocooche
    Codice PHP:
        public int hashCode() {
            
    int hash 7;
            
    hash 19 hash + (this.matricola != null this.matricola.hashCode() : 0);
            
    hash 19 hash + (this.nome != null this.nome.hashCode() : 0);
            
    hash 19 hash + (this.cognome != null this.cognome.hashCode() : 0);
            
    hash 19 hash + (this.citta != null this.citta.hashCode() : 0);
            return 
    hash;
        } 
    Sì, questo è un algoritmo di hash buono e completo che dà anche un "peso" ai vari campi. Questo rende meno probabile una collisione.

    Originariamente inviato da coocooche
    Ora il codice funziona perfettamente ma mi piacerebbe sapere come generare il metodo hashCode() senza l'aiuto del editor (l'ho dovuto generare tramite NetBeans)...
    Più o meno come ha fatto l'IDE.
    La questione è solo quella di rendere meno probabile una "collisione" (che avviene quando due oggetti diversi, nel senso fornito da equals(), danno lo stesso hash code).

    Quindi è solo il fatto della "bontà" dell'algoritmo.

    Esempio banale: se ci fossero 2 int a e b come campi, uno potrebbe ritornare banalmente a + b come hash code, non è sbagliato di per sé. Cosa succede? 2+5 sarebbe uguale a 5+2 ... collisione.
    Se invece si fa es. a*19+b, allora 2*19+5 non è uguale a 5*19+2 !!
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Ho ben accolto il tuo suggerimento e ho modificato equals():
    Codice PHP:
    public boolean equals(Object o) {
          if(
    instanceof Studente) {
             return (
    nome.equals(((Studente)o).nome)) && (cognome.equals(((Studente)o).cognome)) &&
                     (
    citta.equals(((Studente)o).citta)) && (matricola.equals(((Studente)o).matricola));
          } else {
             return 
    false;
          }
        } 
    Originariamente inviato da andbin
    Se si vuole si può anche gestire a priori un caso particolare: se l'oggetto passato è == al this si può ritornare subito un bel true. È solo una ottimizzazione.
    Scusami ma non capisco, cosa intendi con questa frase?

    PS:Ottima spiegazione per quanto riguardo il metodo hashCode()

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da coocooche
    Ho ben accolto il tuo suggerimento e ho modificato equals():
    Codice PHP:
    public boolean equals(Object o) {
          if(
    instanceof Studente) {
             return (
    nome.equals(((Studente)o).nome)) && (cognome.equals(((Studente)o).cognome)) &&
                     (
    citta.equals(((Studente)o).citta)) && (matricola.equals(((Studente)o).matricola));
          } else {
             return 
    false;
          }
        } 
    Usa una variabile, non fare il cast per ogni campo. Sarebbe anche più leggibile.

    Originariamente inviato da coocooche
    Scusami ma non capisco, cosa intendi con questa frase?
    codice:
    if (o == this) {
        return true;
    }
    Se l'oggetto passato fosse, guarda caso, esattamente lo stesso identico oggetto su cui è stato invocato .... allora è chiaro che sono per forza uguali!
    Ma è solo una ottimizzazione.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  9. #9
    Cosi credo il metodo e' ottimizzato:
    Codice PHP:
    public boolean equals(Object o){
            if(
    == this) return true//se 'o' è == al 'this' si ritorna subito true
            
    else{
                if(
    instanceof Studente){ // se 'o' è un istanza di 'Studente'
                   
    Studente s = (Studenteo;
                   return 
    nome.equals(s.nome) && cognome.equals(s.cognome) &&
                          
    citta.equals(s.citta) && matricola.equals(s.matricola);
                }else{
                    return 
    false;
                }
            }
        } 
    Un ultima cosa.
    Se io volessi esprimere che due istanze di tipo Studente sono uguali solamente se solo un campo e' uguale (in questo caso vorrei trattare il campo 'matricola' come 'unique' come nei db), e' di buon norma fare questo tramite il metodo equals?? Secondo il mio ragionamento avro':
    Codice PHP:
    public boolean equals(Object o){
            if(
    == this) return true//se 'o' è == al 'this' si ritorna subito true
            
    else{
                if(
    instanceof Studente){ // se 'o' è un istanza di 'Studente'
                   
    Studente s = (Studenteo;
                   return 
    matricola.equals(s.matricola);
                }else{
                    return 
    false;
                }
            }
        } 

  10. #10
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da coocooche
    Se io volessi esprimere che due istanze di tipo Studente sono uguali solamente se solo un campo e' uguale (in questo caso vorrei trattare il campo 'matricola' come 'unique' come nei db), e' di buon norma fare questo tramite il metodo equals??
    Certamente, va benissimo. Dopotutto il criterio di uguaglianza lo puoi scegliere come preferisci in base a cosa rappresenta la classe e come dovranno essere trattati gli oggetti.

    Devi però continuare a rispettare il "contratto" tra equals() e hashCode(). Un concetto che si deduce dalle varie regole del contratto è che equals() deve essere "accurato" (nel senso di quanti/quali campi prende in considerazione) almeno quanto hashCode().

    Se in hashCode() usassi solo nome e cognome, allora equals() deve usare sicuramente questi due. In equals puoi usarne anche altri in più, eventualmente, ma quelli usati da hashCode devi usarli anche in equals!

    Se l'equals usa solo matricola e continui ad usare il hashCode che ti aveva generato l'IDE (quello che usa i 4 campi), tu "rompi" il contratto tra i due metodi e cose spiacevoli potrebbero capitare se usi gli oggetti nelle collezioni set/map basate su hash table.

    Se ti stai chiedendo perché tutto questo, prova a pensare ad esempio una classe Persona con campi nome, cognome e annoNascita, dove equals() usa solo nome/cognome e hashCode() tutti i 3 campi. Ora immagina di avere 2 oggetti Mario,Rossi,1974 e Mario,Rossi,1935 .... che succede? Sono "uguali" per equals ma hanno (sicuramente) hashCode differenti. Ed è sbagliato. La regola principale: due oggetti uguali devono dare hashCode uguale.
    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.