HashMap che contiene Oggetto di Tipo Persona

di il
11 risposte

HashMap che contiene Oggetto di Tipo Persona

Ciao a tutti,
per esercizio sto implementando una sistema che gestisca le prenotazioni di un volo previa iscrizione ad un determinato sito web.
Come inizio ho impostato le mie classi, tra le quali:

Persona : Che restituisce un oggetto di tipo Persona;
NewSubmit : Che a mia intenzione deve imlementare una HashMap dove aggiungo la coppia <Persona,integer> dove integer è banalmente
un dato incrementale.
Questo il codice delle due classi

La Classe Persona

package volo.prenotazione.model;

public class Persona {
	private String Nome;
	private String Cognome;
	private String DataNascita;
	private String Residenza;
	private String NumeroTel;
	private String EMail;
	
	
	private Persona() {};
	
	public static class NewPersonaBuilder{
		private String Nome;
		private String Cognome;
		private String DataNascita;
		private String Residenza;
		private String NumeroTel;
		private String EMail;
		
			public Persona build() {
				Persona persona=new Persona();
				persona.Nome=this.Nome;
				persona.Cognome=this.Cognome;
				persona.DataNascita=this.DataNascita;
				persona.Residenza=this.Residenza;
				persona.NumeroTel=this.NumeroTel;
				persona.EMail=this.EMail;
				return persona;
			}
			
				public NewPersonaBuilder(String nome) {
					this.Nome=nome;
				}

				public NewPersonaBuilder setNome(String nome) {
					Nome=nome;
					return this;
				}

				public NewPersonaBuilder setCognome(String cognome) {
					Cognome = cognome;
					return this;
				}

				public NewPersonaBuilder setDataNascita(String dataNascita) {
					DataNascita = dataNascita;
					return this;
				}

				public NewPersonaBuilder setResidenza(String residenza) {
					Residenza = residenza;
					return this;
				}

				public NewPersonaBuilder setNumeroTel(String numeroTel) {
					NumeroTel = numeroTel;
					return this;
				}

				public NewPersonaBuilder seteMail(String eMail) {
					EMail = eMail;
					return this;
				}

	}
}
La Classe NewSubmit

package volo.prenotazione.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class NewSubmit {
	HashMap<Persona, Integer> listPersona=new HashMap<Persona, Integer>();
	int idIscrizione;
	private static NewSubmit newsubmit;
	
	public static NewSubmit getIstance() {
		if(newsubmit==null) {
			newsubmit=new NewSubmit();
		}
		
		return newsubmit;
	}
	
	
	public int createSubmit(Persona p) {
		idIscrizione++;
			listPersona.put(p, idIscrizione);
		return idIscrizione;
	}
	
	public void showSubmits() {
		Iterator<Map.Entry<Persona, Integer>> entryset=listPersona.entrySet().iterator();
		while(entryset.hasNext()) {
		Map.Entry<Persona, Integer> entry=entryset.next();
		System.out.println("PERSONA="+entry.getKey()+" "+"ID="+entry.getValue());
		}
	}
}
Oltre che a chiedervi consigli sia sul modo di implementare che di "ragionarla" vi chiederei una cosa:
Con il metodo showSbmits() era mia intenzione stampare ogni "Persona" associata al proprio idIscrizione ma, l'output che ricevo è questo ( che ad occhio e croce credo essere l'indirizzo di memoria dove è allocato l'oggetto Persona associato a quell'Id ) :

PERSONA=volo.prenotazione.model.Persona@4361bd48 ID=1

Potreste spiegarmi come fare per stampare tutte le singole voci sotto forma di "tabella"?

Grazie mille.

11 Risposte

  • Re: HashMap che contiene Oggetto di Tipo Persona

    MarcoRayRaimondi ha scritto:


    Come inizio ho impostato le mie classi, tra le quali:

    Persona : Che restituisce un oggetto di tipo Persona;
    NewSubmit : Che a mia intenzione deve imlementare una HashMap dove aggiungo la coppia <Persona,integer> dove integer è banalmente
    un dato incrementale.
    Partiamo da alcuni aspetti davvero elementari e basilari.

    1) I nomi delle variabili (tutte, compresi i parametri) dovrebbero iniziare con la lettera minuscola, non maiuscola. Questa è una convenzione standard di Java e inoltre serve anche per distinguere bene le variabili dai tipi (che invece iniziano di norma con la maiuscola) in modo da evitare il più possibile scenari di obscuring (non sto adesso a spiegare cosa è).

    2) Non inventarti nomi che cambiano solo nel case, tipo numeroTel e NumeroTel. Se il campo è numeroTel, il parametro del setter (o costruttore o altro metodo) sarà numeroTel e si usa this per qualificare il campo. Stop.

    3) L'uso di un "builder" non è sbagliato, è utile quando in una classe ci sono molti attributi e tanti/tutti sono opzionali. E specialmente se gli oggetti devono essere "immutabili", pur avendo appunto molti attributi opzionali.
    Generalmente però la classe del builder si chiama solamente Builder (se è una nested class) e basta (non NewPersonaBuilder), in modo da poter fare new Persona.Builder() . In alternativa (è un "di più") si può mettere in Persona un metodo statico che tira fuori un nuovo Builder, in modo da fare semplicemente Persona.builder() .

    P.S. NewSubmit come nome forse dice poco, riformula il nome, magari ...

    MarcoRayRaimondi ha scritto:


    l'output che ricevo è questo ( che ad occhio e croce credo essere l'indirizzo di memoria dove è allocato l'oggetto Persona associato a quell'Id ) :

    PERSONA=volo.prenotazione.model.Persona@4361bd48 ID=1
    Questa forma è semplicemente il risultato del toString() che è ereditato dalla classe Object, dato che NON è stato ridefinito in Persona. Quindi è sufficiente ridefinire il metodo toString() in Persona per fornire una descrizione più significativa.


    E comunque c'è un'altra questione. Hai usato gli oggetti Persona come "chiavi" del HashMap. Affinché un oggetto possa funzionare bene e correttamente come chiave di un HashMap (e in generale di altre map basate su hash-table interna), la classe dell'oggetto deve ridefinire appropriatamente i metodi equals(Object) e hashCode() in modo da mantenere valido il "contratto" che esiste tra questi due metodi. Nella tua classe Persona non si vede nulla a riguardo.
    Ah .. e gli oggetti che si usano come "chiavi" di queste map dovrebbero essere "immutabili".

    Consiglio di rivedere bene/meglio le basi di Java.
  • Re: HashMap che contiene Oggetto di Tipo Persona

    Mille grazie!

    Vorrei solo chiederti cosa intendi quando dici questo:
    Ah .. e gli oggetti che si usano come "chiavi" di queste map dovrebbero essere "immutabili".
    Cosa Intendi dire con "Immutabili"?
    Consiglio di rivedere bene/meglio le basi di Java.
    Sto studiando proprio per questo, sono al secondo mese di studio.
    In realtà sono un umile pigia tasti appassionato di informatica.

    Grazie mille ancora
  • Re: HashMap che contiene Oggetto di Tipo Persona

    MarcoRayRaimondi ha scritto:


    Ah .. e gli oggetti che si usano come "chiavi" di queste map dovrebbero essere "immutabili".
    Cosa Intendi dire con "Immutabili"?
    Un oggetto è "immutabile" se dopo che è stato istanziato non è più possibile modificare il suo stato. In sostanza vuol dire: nessun metodo setter (setXyz) o altro metodo che possa modificare lo stato. E generalmente/tipicamente i campi sono messi come private final.

    La immutabilità ha vari benefici, specialmente nell'ambito del multi-threading. Ma nel caso delle map, è importante che le chiavi siano immutabli. Se un oggetto mutabile viene usato come chiave, se è già nella map e tu, avendo tenuto il reference, vai a modificarne lo stato, si rischia (non è detto al 100%) che poi dopo quella chiave non si riesca più a trovarla!
    (e nota: anche se equals/hashCode fossero perfettamente implementati!)
  • Re: HashMap che contiene Oggetto di Tipo Persona

    Un oggetto è immutabile quando, dopo essere stato istanziato, non può più essere modificato.
    In pratica, la classe non possiede metodi setter (e nemmeno campi pubblici, ma lo dò per scontato) e l'unico modo per poter popolare i valori del suo stato interno è il costruttore (o metodi privati utilizzati dal builder, se esiste).
  • Re: HashMap che contiene Oggetto di Tipo Persona

    E comunque c'è un'altra questione. Hai usato gli oggetti Persona come "chiavi" del HashMap. Affinché un oggetto possa funzionare bene e correttamente come chiave di un HashMap (e in generale di altre map basate su hash-table interna), la classe dell'oggetto deve ridefinire appropriatamente i metodi equals(Object) e hashCode() in modo da mantenere valido il "contratto" che esiste tra questi due metodi. Nella tua classe Persona non si vede nulla a riguardo.
    Eccoci...ho capito!!
    Non da meno, ho visto che se creo un oggetto con email uguale nemmeno lo inserisce!!!!
    
    @Override
    	public int hashCode() {
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + ((email == null) ? 0 : email.hashCode());
    		return result;
    	}
    
    
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Persona other = (Persona) obj;
    		if (email == null) {
    			if (other.email != null)
    				return false;
    		} else if (!email.equals(other.email))
    			return false;
    		return true;
    	}
    
    E generalmente/tipicamente i campi sono messi come private final.
    Tipo così?
    
    public final NewPersonaBuilder setNome(String Nome) {
    					nome=Nome;
    					return this;
    				}
    
    				public final NewPersonaBuilder setCognome(String Cognome) {
    					cognome = Cognome;
    					return this;
    				}
    
    				public final NewPersonaBuilder setDataNascita(String dataNascita) {
    					datanascita = dataNascita;
    					return this;
    				}
    
    				public final NewPersonaBuilder setResidenza(String Residenza) {
    					residenza = Residenza;
    					return this;
    				}
    
    				public final NewPersonaBuilder setNumeroTel(String numeroTel) {
    					numerotel = numeroTel;
    					return this;
    				}
    
    				public final NewPersonaBuilder seteMail(String eMail) {
    					email = eMail;
    					return this;
    				}
    
    Grazie!!
  • Re: HashMap che contiene Oggetto di Tipo Persona

    MarcoRayRaimondi ha scritto:


    Eccoci...ho capito!!
    Non da meno, ho visto che se creo un oggetto con email uguale nemmeno lo inserisce!!!!
    Sei tu che devi stabilire cosa vuol dire che due distinti oggetti Persona sono "uguali". Quando hanno stesso nome+cognome? Quando hanno stessa email? ecc...
    Le map non accettano chiavi "duplicate", quindi il criterio che stabilisci influisce sul fatto di non poter inserire come chiave un altro oggetto "uguale".

    MarcoRayRaimondi ha scritto:


    Tipo così?
    
    public final NewPersonaBuilder setNome(String Nome) {
    					nome=Nome;
    					return this;
    				}
    
    				public final NewPersonaBuilder setCognome(String Cognome) {
    					cognome = Cognome;
    					return this;
    				}
    
    				public final NewPersonaBuilder setDataNascita(String dataNascita) {
    					datanascita = dataNascita;
    					return this;
    				}
    
    				public final NewPersonaBuilder setResidenza(String Residenza) {
    					residenza = Residenza;
    					return this;
    				}
    
    				public final NewPersonaBuilder setNumeroTel(String numeroTel) {
    					numerotel = numeroTel;
    					return this;
    				}
    
    				public final NewPersonaBuilder seteMail(String eMail) {
    					email = eMail;
    					return this;
    				}
    
    NO. I metodi del builder non devono per forza essere final (generalmente non lo sono!). E sempre nel builder i suoi campi non vanno di certo final (perché il builder è mutabile!).
    E' la classe Persona che può avere i campi final, se intendi rendere i suoi oggetti immutabili.
  • Re: HashMap che contiene Oggetto di Tipo Persona

    E' la classe Persona che può avere i campi final, se intendi rendere i suoi oggetti immutabili.
    Ciao, dunque se non ho capito male per rendere un oggetto immutabile vanno seguiti alcuni criteri:
  • Re: HashMap che contiene Oggetto di Tipo Persona

    MarcoRayRaimondi ha scritto:


    1. Dichiarare la classe come final;
    Non è strettamente necessario. Il fatto di rendere la classe final è principalmente solo per impedire che "qualcuno" possa ridefinire in modo inappropriato i metodi o peggio aggiungere dello stato mutabile, cosa che vanificherebbe gli obiettivi della immutabilità complessiva dell'oggetto.

    Insomma, se sei solo tu che usi la classe e "sai" quello che stai facendo, non è una grossa questione. Uno potrebbe fare una classe Punto2D immutabile e poi voler fare una sottoclasse Punto2DColorato (che aggiunge un colore) ma di nuovo immutabile.

    E' più una questione della ampiezza di utilizzo e a chi va in mano la classe ...

    MarcoRayRaimondi ha scritto:


    2. Dichiarare tutti i campi come private final;
    Sì.

    MarcoRayRaimondi ha scritto:


    3.Assicurarsi che non ci siano metodi che possano cambiare gli attributi della classe ( setXxx );
    Sì. Ma d'altronde, se i campi sono final non li potresti comunque modificare.

    MarcoRayRaimondi ha scritto:


    4.Fornire, quindi, solo metodi di tipo getter;
    Sì.

    MarcoRayRaimondi ha scritto:


    4. In caso debba essere restituito un tipo di oggetto farlo ma tramite una copia dell'oggetto stesso;
    Se è necessario fare una copia "difensiva" o no, dipende se quell'attributo è di una classe di oggetti mutabili oppure no.

    MarcoRayRaimondi ha scritto:


    Per la classe Persona, così è giusto?:
    Sì, è tecnicamente corretta (a parte eventuali equals/hashCode/ecc... da aggiungere).

    MarcoRayRaimondi ha scritto:


    così facendo, non decade la possibilità di utilizzare il Pattern Builder?
    No, il Builder lo puoi comunque applicare. E anzi, lo devi fare se vuoi che l'utilizzatore di Persona possa creare un oggetto senza usare il costruttore completo ma solo passando giusto "alcuni" dati.

    Il Builder naturalmente utilizzerebbe quel costruttore completo. Ma l'utilizzatore potrebbe fare (scrivo solo Persona per semplicità):

    Persona p = new Persona.Builder().nome("Andrea").build();

    invece di dover fare

    Persona p = new Persona("Andrea", null, null, null, null, null);

    che è meno bello e meno "parlante" (oltre che più lungo).
  • Re: HashMap che contiene Oggetto di Tipo Persona

    Il Builder naturalmente utilizzerebbe quel costruttore completo. Ma l'utilizzatore potrebbe fare (scrivo solo Persona per semplicità):
    Scusami, potresti farmi un accenno di codice per capire come implementare il costruttore seguendo il Pattern Builder.
    Sto provando a capire ma non riesco a risolvere gli errori di sintassi..non capisco.
    
    package volo.prenotazione.model;
    
    public final class Persona implements UserPersona {
    	private String nome = "";
    	private String cognome = "";
    	private String datanascita = "";
    	private String residenza = "";
    	private String numerotel = "";
    	private String email = "";
    	
    	public static class Builder{
    		private  String nome;
    		private  String cognome;
    		private  String datanascita;
    		private  String residenza;
    		private  String numerotel;
    		private  String email;
    		
    			public Persona build() {
    				Persona persona=new Persona();
    				persona.nome=this.nome;
    				persona.cognome=this.cognome;
    				persona.datanascita=this.datanascita;
    				persona.residenza=this.residenza;
    				persona.numerotel=this.numerotel;
    				persona.email=this.email;
    				return persona;
    			}
    			
    				public   Builder(String nome) {
    					this.nome=nome;
    				}
    
    				public Builder setNome(String Nome) {
    					nome=Nome;
    					return this;
    				}
    				
    				....
    				....
    				....
    }
    	
    	
    	public final String toString() {
    		String concatena;
    		concatena="\n"+this.nome+"\n"+this.cognome+"\n"+this.datanascita+"\n"+this.residenza+"\n"+this.numerotel+"\n"+this.email;
    		return concatena;
    	}
    
    
    	@Override
    	public int hashCode() {
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + ((email == null) ? 0 : email.hashCode());
    		return result;
    	}
    
    
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Persona other = (Persona) obj;
    		if (email == null) {
    			if (other.email != null)
    				return false;
    		} else if (!email.equals(other.email))
    			return false;
    		return true;
    	}
    }				
    				
    
    Con attributi private final:
    
    package volo.prenotazione.model;
    
    public final class Persona implements UserPersona {
    	private private final String nome = "";  // err = Duplicate Modifier For The Field "nome"
    	private private final String cognome = "";//err = Duplicate Modifier For The Field "cognome"
    	private String datanascita = "";
    	private String residenza = "";
    	private String numerotel = "";
    	private String email = "";
    	
    	public static class Builder{
    		private  String nome;
    		private  String cognome;
    		private  String datanascita;
    		private  String residenza;
    		private  String numerotel;
    		private  String email;
    		
    			public Persona build() {
    				Persona persona=new Persona();
    				persona.nome=this.nome;
    				persona.cognome=this.cognome;
    				persona.datanascita=this.datanascita;
    				persona.residenza=this.residenza;
    				persona.numerotel=this.numerotel;
    				persona.email=this.email;
    				return persona;
    			}
    			
    				public   Builder(String nome) {
    					this.nome=nome;
    				}
    
    				public Builder setNome(String Nome) {
    					nome=Nome;
    					return this;
    				}
    				
    				...
    				...
    				...
    }
    	
    	
    	public final String toString() {
    		String concatena;
    		concatena="\n"+this.nome+"\n"+this.cognome+"\n"+this.datanascita+"\n"+this.residenza+"\n"+this.numerotel+"\n"+this.email;
    		return concatena;
    	}
    
    
    	@Override
    	public int hashCode() {
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + ((email == null) ? 0 : email.hashCode());
    		return result;
    	}
    
    
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Persona other = (Persona) obj;
    		if (email == null) {
    			if (other.email != null)
    				return false;
    		} else if (!email.equals(other.email))
    			return false;
    		return true;
    	}
    }
    
    Grazie infinite!!
  • Re: HashMap che contiene Oggetto di Tipo Persona

    MarcoRayRaimondi ha scritto:


    Scusami, potresti farmi un accenno di codice per capire come implementare il costruttore seguendo il Pattern Builder.
    Sto provando a capire ma non riesco a risolvere gli errori di sintassi..non capisco.
    Partiamo da un aspetto: fare subito una inizializzazione esplicita del campo può aver senso solo se "mutabile".
    Se metti il campo final e poi lo inizializzi subito con ="" allora poi neanche un costruttore sarebbe in grado di inizializzarlo! E diventerebbe quindi una classe di fatto inutile e inutilizzabile.

    Riguardo l'errore di sintassi, è banale: hai scritto 2 volte private. Questo è illegale, non si possono ripetere i modificatori.

    private private final String nome = ""; // err = Duplicate Modifier For The Field "nome"


    Pertanto, se vuoi fare una classe Persona "immutabile" e costruibile anche con un builder:

    1) Classe Persona final (ripeto quanto già detto, final non è strettamente necessario ma è comunque tipico e preferibile)
    2) Campi private final
    3) Almeno 1 costruttore esplicito, ragionevolmente quello che riceve tutti i dati e li assegna ai campi
    4) Solo metodi "getter"
    5) Altro eventuale (equals, ecc...)

    Per il builder:

    6) Classe nested (static) chiamata, tipicamente, Builder
    7) Campi private (non final !!)
    8) Metodi che settano i dati nel builder. Si può chiamarli setXyz ma siccome il builder non è un "normale" bean, generalmente si tende a togliere "set", quindi solo es. nome(String nome) . Anche perché così è più "fluente".
    9) Eventuale costruttore ma generalmente solo se c'è da preimpostare dei dati "obbligatori".
    10) Metodo "finale" build() che crea l'oggetto immutabile (più eventuale pre-validazione dei dati, se necessario)

    Tutto qui. Il builder generalmente NON ha bisogno di equals/hashCode. Può aver senso un toString() ai fini di debugging/logging.
  • Re: HashMap che contiene Oggetto di Tipo Persona

    Riguardo l'errore di sintassi, è banale: hai scritto 2 volte private. Questo è illegale, non si possono ripetere i modificatori.

    private private final String nome = ""; // err = Duplicate Modifier For The Field "nome"
    Che vergogna!! Chiedo Perdono! Ero talmente fasciato che manco me ne sono accorto!
    Pertanto, se vuoi fare una classe Persona "immutabile" e costruibile anche con un builder:

    1) Classe Persona final (ripeto quanto già detto, final non è strettamente necessario ma è comunque tipico e preferibile)
    2) Campi private final
    3) Almeno 1 costruttore esplicito, ragionevolmente quello che riceve tutti i dati e li assegna ai campi
    4) Solo metodi "getter"
    5) Altro eventuale (equals, ecc...)

    Per il builder:

    6) Classe nested (static) chiamata, tipicamente, Builder
    7) Campi private (non final !!)
    Metodi che settano i dati nel builder. Si può chiamarli setXyz ma siccome il builder non è un "normale" bean, generalmente si tende a togliere "set", quindi solo es. nome(String nome) . Anche perché così è più "fluente".
    9) Eventuale costruttore ma generalmente solo se c'è da preimpostare dei dati "obbligatori".
    10) Metodo "finale" build() che crea l'oggetto immutabile (più eventuale pre-validazione dei dati, se necessario)
    GRAZIE
    Tutto qui. Il builder generalmente NON ha bisogno di equals/hashCode. Può aver senso un toString() ai fini di debugging/logging.
    ANCORA GRAZIE!!!

    Potessi ti offrirei una cena!!!
    Anche solo per la pazienza!!

    Buon Fine Settimana!!
Devi accedere o registrarti per scrivere nel forum
11 risposte