View Full Version : [JAVA] Alcune perplessità riguardo le classi...
InsomNia_Italy
17-06-2009, 18:36
Ciao a tutti.
Sto facendo un po di pratica nella programmazione Java ed un po alla volta sto riuscendo e capendo il funzionamento del tutto. Portate pazienza se non sarò tecnico :)
Questo pomeriggio stavo provando a creare un programmino semplice semplice per l'immissione in array di oggetti di Classi scolastiche e relativi Alunni di ogni classe. Ho creato due classi, proprio ALUNNO e CLASSESCUOLA. Pubblico qui il codice completo:
import java.io.*;
import java.util.*;
public class Scuola{
static int sizeClassiScuola = 0;
private static CLASSESCUOLA [] classescuola = new CLASSESCUOLA[50];
static BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) );
public static void main(String args[]) throws IOException{
//-------------------------------------------------------
for(;;){
System.out.println("-----------------------------------------------");
System.out.println("Rubrica elettronica Scuola");
System.out.println();
System.out.println("1) Visualizza classi e alunni");
System.out.println("2) Aggiungi nuova classe");
System.out.println("0) Chiudere rubrica");
System.out.println();
//-------------------------------------------------------
int Scelta = 0;
ciclo: for(;;){
System.out.print("Inserire il numero della tua scelta: ");
Scelta = Integer.parseInt(in.readLine());
switch(Scelta){
case 1:
if (sizeClassiScuola>0){
//VISUALIZZARE CONTATTI
Scuola.VisualizzaClassi();
in.readLine();
}else{
System.out.println("Nessuna classe da visualizzare!");
in.readLine();
}
break ciclo;
case 2:
//AGGIUNGI NUOVA CLASSE
Scuola.AggiungiClasse();
break ciclo;
case 0:
//CHIUDERE RUBRICA
System.out.println("Chiusura agenda...");
System.exit(0);
default:
//SCELTA NON VALIDA
System.out.println("Scelta non valida");
}
}}
}
public static void AggiungiClasse() throws IOException{
int quanteClassi = 0;
String nuovonome = "";
String linea = "";
System.out.print("Quante classi vuoi aggiungere?: ");
quanteClassi = Integer.parseInt(in.readLine());
System.out.println("-----------------------------------------------");
System.out.println("I dati vanno inseriti nella forma: ( IA - IIB - IIIC - IVD - VE)");
//CICLO DI ACQUISIZIONE
int sizePreAcquisizione = sizeClassiScuola;
for (int contClasse=0;contClasse<quanteClassi;contClasse++){
System.out.print("Classe " + (contClasse+1) + " su "+ quanteClassi + ":");
nuovonome = in.readLine();
System.out.print("Quanti alunni vuoi aggiungere nella " + nuovonome + "?: ");
int QuantiAlunni = Integer.parseInt(in.readLine());
classescuola[contClasse+sizePreAcquisizione] = new CLASSESCUOLA(nuovonome,QuantiAlunni);
sizeClassiScuola++;
System.out.println("-----------------------------------------------");
System.out.println("I dati vanno inseriti nella forma: COGNOME NOME");
//CICLO DI ACQUISIZIONE
for (int contAlunni=0;contAlunni<QuantiAlunni;contAlunni++){
System.out.print("Nominativo " + (contAlunni+1) + " su "+ QuantiAlunni + ":");
linea = in.readLine();
//SPEZZO LA STRINGA
StringTokenizer tz = new StringTokenizer(linea);
String cognome = tz.nextToken();
String nome = tz.nextToken();
classescuola[contClasse].newAlunno(cognome, nome, contAlunni);
}
}
}
public static void VisualizzaClassi() throws IOException{
for (int cont=0;cont<sizeClassiScuola;cont++){
System.out.println(cont+1 + "° Classe: " + classescuola[cont].getClasse());
System.out.println("\t Alunni che compongono la classe:");
for (int cont2=0;cont2<classescuola[cont].getNumeroAlunni();cont2++){
System.out.println("\t - " + classescuola[cont].getAlunno(cont2).getCognome() + " " + classescuola[cont].getAlunno(cont2).getNome());
}
}
}
} //FINE CLASSE RUBRICA
class ALUNNO{
private String cognome;
private String nome;
public ALUNNO(String cogn,String nom) {
cognome = cogn;
nome = nom;
}
public String getCognome(){
return cognome;
}
public String getNome(){
return nome;
}
} //FINE CLASSE ALUNNO
class CLASSESCUOLA{
private ALUNNO [] al = new ALUNNO[50];
private String classe;
private Integer numeroAlunni;
public CLASSESCUOLA(String cl,Integer numAlunni) {
classe = cl;
numeroAlunni = numAlunni;
}
public String getClasse(){
return classe;
}
public Integer getNumeroAlunni(){
return numeroAlunni;
}
public ALUNNO getAlunno(Integer Indice){
return al[Indice];
}
public String newAlunno(String Cognome,String Nome,Integer Cont){
al[Cont] = new ALUNNO(Cognome,Nome);
return null;
}
} //FINE CLASSE CLASSESCUOLA
Il programma in se funziona ma ho alcune perplessità. E' necessario implementare all'interno della classe CLASSESCUOLA il codice:
public String newAlunno(String Cognome,String Nome,Integer Cont){
al[Cont] = new ALUNNO(Cognome,Nome);
return null;
}
per poter aggiungere un nuovo alunno all'interno della classe?
Devo necessariamente specificare l'indice di ogni nuovo alunno creato?
Non esiste un modo più semplice per aggiungere un nuovo alunno in coda a quelli precedentemente creati, qualora ce ne fossero?
Altra cosa.
Devo necessariamente specificare ogni volta il numero di oggetti da creare?
private ALUNNO [] al = new ALUNNO[50];
Come posso rendere il tutto automatico per evitare errori di NullPointetc...?
Ultima domanda
All'interno del metodo VisualizzaClassi utilizzo
classescuola[cont].getAlunno(cont2).getCognome()
Va bene cosi oppure mi conviene dichiarare l'oggetto ALUNNO di tipo public ed utilizzare direttamente
classescuola[cont].al[cont2].getCognome() senza utlizzare il metodo getAlunno della classe CLASSESCUOLA?
Grazie, spero possiate aiutarmi :)
carter100
17-06-2009, 18:57
Premetto che tutto il codice non l'ho visto, è una enormità.
Per il primo dubbio, sull'indice e sugli elementi del vettore, se usi la classe ArrayList hai una allocazione dinamica, è semplice da usare.
Per l'ultimo dubbio, non ho tempo ora di dare 1 sguardo al codice, in ogni caso se usi un arraylist avrai il metodo get per recuperare l'alunno all'indice i, quindi quel rigo un pò andrà modificato uguale
morskott
17-06-2009, 20:42
Non ho ancora visto il codice, ma se invece di avere un array che ti devi gestire indici e a creazione a dimensione prefissata immutabile usi invece un oggetto "List"? per inserire basta chiamare il metodo "add", per accedere il metodo "get" che prende come parametro l'indice al quale vuoi accedere e se poi ci saà un posto dove devi per forza usare un array ci puoi invocare il metodo "toArray" che ti restituisce un array del contenuto.
Poi io non lascerei vedere all'esterno gli indici, ho intravisto un public String newAlunno(String Cognome,String Nome,Integer Cont){
al[Cont] = new ALUNNO(Cognome,Nome);
return null;
} che impone al chiamante la conoscenza della struttura dati interna su cui agisci, permettendogli per esempio di generarti un IndexOutOfRangeException in caso ti metta un indice superiore al massimo consentito o peggio ancora di sovrascriverti oggetti già presenti, al massimo se devi proprio utilizzare un array dentro alla classe di definizione farei public class XXX{
//altro
private Alunno[] alunni;
private int indiceAlunni;
public XXX(){
this.alunni=new Alunni[size];
this.indiceAlunni=0;
}
public void addAlunno(String nome,String cognome){
this.alunni[this.indiceAlunni]=new Alunno(nome,cognome);
this.indiceAlunni++;
}
}
Se invece usi un oggetto List
public class XXX{
private List<Alunno> listaAlunni;
public XXX(){
this.listaAlunni=new ArrayList<Alunno>(); //oppure anche new LinkedList<Alunno>()
}
public void addAlunno(String nome,String cognome){
this.listaAlunni.add(new Alunno(nome,cognome));
}
}.
Mo leggiucchio il codice.
morskott
17-06-2009, 21:22
Ho visionato il codice, mi sembra un po di non facilissima comprensione e facile da malintendere, ne ho fatta una mia versione del tuo programma, vedi se ti puo dare qualche hintimport java.util.*;
public class MainScuola{
private Scuola scuola;
private static final String VIS="1";
private static final String INS="2";
private static final String EXIT="3";
public MainScuola(String nomeScuola){
this.scuola=new Scuola(nomeScuola);
}
public void visualizzaScuola(){
System.out.println("Visualizzando la scuola:"+this.scuola.getNome());
Set<Classe> leClassi=this.scuola.getClassi();
for (Classe classe:leClassi){
System.out.println("Visualizzando la classe:"+classe.getNome());
Set<Alunno> gliAlunni=classe.getAlunni();
for (Alunno alunno:gliAlunni){
System.out.println("Visualizzando l'alunno:"+alunno.getNome()+" "+alunno.getCognome());
}
}
}
public void aggiungiClasse(){
Scanner scanner=new Scanner(System.in);
System.out.print("Inserisci il nome della classe:");
Classe classe=new Classe(scanner.nextLine());
System.out.println("Inserire alunni (q per terminare)");
while (true){ //soluzione "sporca" ma in 3 sec mi viene in mente questa
System.out.print("Nome alunno\n>>");
String nomeAlunno=scanner.nextLine();
if (nomeAlunno.equals("q")) break;
System.out.print("Cognome alunno\n>>");
String cognomeAlunno=scanner.nextLine();
if (cognomeAlunno.equals("q")) break;
Alunno alunno=new Alunno(nomeAlunno,cognomeAlunno);
classe.addAlunno(alunno);
}
this.scuola.addClasse(classe);
}
public void run(){
System.out.println("Benvenuti alla rubrica elettronica della scuola "+this.scuola.getNome());
boolean continua=true;
Scanner scanner=new Scanner(System.in);
while (continua){
System.out.print(VIS+") per visualizzare la scuola\n"+INS+") per inserire classi\n"+EXIT+") per uscire\n>>");
String input=scanner.nextLine();
if (input.equals(VIS)){
this.visualizzaScuola();
}
if (input.equals(INS)){
this.aggiungiClasse();
}
if (input.equals(EXIT)){
continua=false;
}
}
}
public static void main(String[] args){
MainScuola main=new MainScuola("Montessori");
main.run();
}
}
class Scuola{
private String nome;
private Set<Classe> leClassi;
public Scuola(String nome){
this.nome=nome;
this.leClassi=new HashSet<Classe>();
}
public String getNome(){
return this.nome;
}
public void addClasse(Classe c){
this.leClassi.add(c);
}
public Set<Classe> getClassi(){
Set<Classe> ris=new HashSet<Classe>();
ris.addAll(this.leClassi);
return ris;
}
}
class Classe{
private String nome;
private Set<Alunno> gliAlunni;
public Classe(String nome){
this.nome=nome;
this.gliAlunni=new HashSet<Alunno>();
}
public String getNome(){
return this.nome;
}
public void addAlunno(Alunno al){
this.gliAlunni.add(al);
}
public Set<Alunno> getAlunni(){
Set<Alunno> ris=new HashSet<Alunno>();
ris.addAll(this.gliAlunni);
return ris;
}
}
class Alunno{
private String nome;
private String cognome;
public Alunno(String nome,String cognome){
this.nome=nome;
this.cognome=cognome;
}
public String getNome(){
return this.nome;
}
public String getCognome(){
return this.cognome;
}
}
InsomNia_Italy
17-06-2009, 22:50
Mamma mia, ti ringrazio moltissimo!
Domani me lo studio per bene, in caso di dubbi chiederò :)
Grazie ancora!! E' decisamente più pulito il tuo codice :)
morskott
18-06-2009, 00:18
In questo modo le informazioni son tutte su ram, quindi quando chiudi il programma perdi tutti i dati, se vuoi renderli permanenti li puoi mettere su files, il modo più semplice è usando un oggetto ObjectOutputStream per scrivere su file e ObjectInputStream per leggerci, ma andrebbero fatte lievissime modifiche al codice, la javadoc ti sarà utilissima!!!
Poi ricorda che è tutto un fatto di "responsabilità", cioè i metodi devon sapere il minimo indispensabile sul resto dell'implementazione, se vedi per aggiungere un Alunno ad una Classe si invoca il metodo"addAlunno" senza nemmeno sapere cosa succede dietro, perchè la responsabilità di aggiungere un Alunno ce l'ha la Classe, se un domani devo modificare una Classe facendogli registrare un Alunno, per esempio, su una macchina remota o ho altre esigenze devo solo o estendere la Classe facendo overriding del metodo o riscrivere solo e solamente il codice della Classe lasciando le altri parti intonse.
I "getClassi" e "getAlunni" fanno una copia dei Set per far in modo che i chiamanti non possano modificare la mia propria struttura dati, rimuovendomi o aggiungendomi oggetti fuori dal mio controllo (fuori dal controllo della classe "Scuola" o "Classe")
banryu79
18-06-2009, 09:57
I "getClassi" e "getAlunni" fanno una copia dei Set per far in modo che i chiamanti non possano modificare la mia propria struttura dati, rimuovendomi o aggiungendomi oggetti fuori dal mio controllo (fuori dal controllo della classe "Scuola" o "Classe")
Se dei dati tornati da quei due metodi si vogliono rendere possibili solo operazioni di lettura, un'alternativa potrebbe essere quella di ritornare una versione "immodificabile" (unmodifiable) della collezione stessa (in questo caso un Set) per esempio così:
...
public Set<Alunno> getAlunni(){
return Collections.unmodifiableSet(this.gliAlunni);
}
In questo modo non si consente al chiamate di modificare in alcun modo il Set (se tenta di farlo direttamente o tramite iteratore viene sollevata un'eccezione di tipo UnsupportedOperationException) ma solo di leggerlo.
Il leggero vantaggio in termini prestazionali è dato dal fatto che il Set non viene duplicato ad ogni chiamata.
La classe di utilità "Collections" si trova sempre nel package java.util.
Per chi è più curioso e vuole un'idea di come siano implementate versioni immodificabili delle collezioni, posto questo link (http://www.docjar.org/html/api/java/util/Collections.java.html).
InsomNia_Italy
18-06-2009, 15:12
In questo modo le informazioni son tutte su ram, quindi quando chiudi il programma perdi tutti i dati, se vuoi renderli permanenti li puoi mettere su files, il modo più semplice è usando un oggetto ObjectOutputStream per scrivere su file e ObjectInputStream per leggerci, ma andrebbero fatte lievissime modifiche al codice, la javadoc ti sarà utilissima!!
Si la gestione dei files (lettura / scrittura) l'ho testata l'altro giorno. Non è affatto difficile...almeno per quello che ho dovuto farci io :)
morskott
18-06-2009, 15:27
Puoi scrivere su files interi oggetti, senza fare scritture campo per campo, basta che implementi per la classe che vuoi salvare l'interfaccia Serializable e che tutti gli oggetti d'istanza facciano lo stesso.
InsomNia_Italy
18-06-2009, 15:32
Ok, avrei qualche domandina per chiarirmi le idee:
class Classe{
private String nome;
private Set<Alunno> gliAlunni;
public Classe(String nome){
this.nome=nome;
this.gliAlunni=new HashSet<Alunno>();
}
public String getNome(){
return this.nome;
}
public void addAlunno(Alunno al){
this.gliAlunni.add(al);
}
public Set<Alunno> getAlunni(){
Set<Alunno> ris=new HashSet<Alunno>();
ris.addAll(this.gliAlunni);
return ris;
}
}
Qui ad esempio utilizzi private Set<Alunno> gliAlunni.
Corrisponde a private Alunno[] gliAlunni che crea gliAlunni di tipo Alunno[]?
Bisogna utilizzare Set perchè stai utilizzando poco dopo HashSet che corrisponde più o meno a:
ALUNNO gliAlunni= new ALUNNO[16] oppure no? Solo che utilizzando HashSet non avrai bisogno non dovrai preoccuparti del limite di numero degli oggetti creati no?
Ultima cosa, nel metodo aggiungiClasse verso la fine fai:
Alunno alunno=new Alunno(nomeAlunno,cognomeAlunno);
classe.addAlunno(alunno);
Come fa a sapere in quale oggetto classe deve creare i nuovi alunni se non specifichi nessun indice? Li inserisce nell'ultimo oggetto classe creato?
Grazie per l'aiuto :)
banryu79
18-06-2009, 16:39
Qui ad esempio utilizzi private Set<Alunno> gliAlunni.
Corrisponde a private Alunno[] gliAlunni che crea gliAlunni di tipo Alunno[]?
Come concetto, se ho capito ciò che intendi, diciamo di sì, nel senso che dichiara un insieme di oggetti di tipo Alunno, così come
private Alunno[] gliAlunni;
dichiara un array (che possiamo considerare un insieme) di oggetti di tipo Alunno.
Tecnicamente sono due cose molto differenti.
Uno è un array di oggetti di tipo Alunno.
L'altro è una collezione, più precisamente un Set, di oggetti di tipo Alunno.
Le collezioni (Collection Framework) le trovi nel JDK della Sun, nel package java.util.
Gli array sono compresi nel linguaggio invece :D
Se usi un array è tua la responsabilità di dimensionarlo, gestirlo, stare atento agli indici e vattelapesca vari.
Quando usi una collezione del JDK, hai invece per le mani un oggetto e quindi operi con i metodi che quell'oggetto ti mette a disposizione. Esistono vari tipi di "contenitori", ognuno dei quali ha delle caratteristiche ben precise e viene usato in preferenza agli altri a seconda dello scopo specifico.
Bisogna utilizzare Set perchè stai utilizzando poco dopo HashSet che corrisponde più o meno a:
ALUNNO gliAlunni= new ALUNNO[16] oppure no?
Set è un interfaccia. HashSet è una classe concreta che implementa l'interfaccia Set.
HashSet internamente usa come contenitore dei dati una HashMap, non un array. Il fatto che sia un Set (dato che ne implementa l'interfaccia) significa che ha le caratteristiche di Set. Per esempio una caratteristica di Set è che non ammette elementi duplicati al suo interno. Quindi se provi a inserire due volte lo stesso Alunno, il secondo inserimento verrà ignorato (il metodo add() di Set torna un boolean: vero se l'elemento è stato inserito, falso se non è stato inserito).
Inoltre, a differenza di un array, un Set non è a accesso casuale ai suoi elementi. Ovvero se con un array puoi dire:
// supponiamo che 'arrayAlunni' sia un'istanza di tipo Alunno[]
Alunno decimoAlunno = arrayAlunni[9];
e ottenere il decimo Alunno inserito nell'array, perchè l'array mantiene gli elementi indicizzati, con Set non hai questa possibilità di accesso.
A ben guardare, per quello che si può supporre dell'uso che farai degli Alunni nella tua applicazione, probabilmente non avrai mai la neccessità di accedere ad un Alunno specificato in base all'indice di posizione nella collezione.
Sarà più probabile che, dati tutti gli Alunni di una Classe, avrai la neccessità o di scandirli tutti uno a uno, oppure avrai bisogno di un Alunno specifico, ma in quel caso lo identificherai rispetto al suo nome/cognome, non alla posizione nella collezione.
Solo che utilizzando HashSet non avrai bisogno non dovrai preoccuparti del limite di numero degli oggetti creati no?
Esatto. Questo perchè appunto tu passi un Alunno da inserire dentro il Set (HashSet) chiamando il suo metodo 'add' e passandogli come argomento l'elemento (l'Alunno) da inserire, senza preoccuparti di altro.
La gestione interna a HashSet degli elementi (come sono memorizzati, dove, quanti ce ne sono) a te non interessa, e viene svolta dietro le quinte da HashSet stesso (come detto prima, tra l'altro internamente non usa neanche un array per memorizzare gli elementi, ma una HashMap; questo per avere dei vantaggi prestazionali per certe operazioni, ed è uno dei motivi che spingono a scegliere di utilizzare una collezione piuttosto che un'altra).
Ultima cosa, nel metodo aggiungiClasse verso la fine fai:
Alunno alunno=new Alunno(nomeAlunno,cognomeAlunno);
classe.addAlunno(alunno);
Come fa a sapere in quale oggetto classe deve creare i nuovi alunni se non specifichi nessun indice? Li inserisce nell'ultimo oggetto classe creato?
Parli del metodo 'aggiungiClasse' della classe MainScuola postata da morskott:
public void aggiungiClasse(){
Scanner scanner=new Scanner(System.in);
System.out.print("Inserisci il nome della classe:");
Classe classe=new Classe(scanner.nextLine());
System.out.println("Inserire alunni (q per terminare)");
while (true){ //soluzione "sporca" ma in 3 sec mi viene in mente questa
System.out.print("Nome alunno\n>>");
String nomeAlunno=scanner.nextLine();
if (nomeAlunno.equals("q")) break;
System.out.print("Cognome alunno\n>>");
String cognomeAlunno=scanner.nextLine();
if (cognomeAlunno.equals("q")) break;
Alunno alunno=new Alunno(nomeAlunno,cognomeAlunno);
classe.addAlunno(alunno);
}
this.scuola.addClasse(classe);
Se guardi il metodo concentrandoti nell'uso che fa dei due oggetti 'classe' di tipo Classe e 'alunno' di tipo Alunno e tieni presente la definizione della classe Classe:
class Classe{
private String nome;
private Set<Alunno> gliAlunni;
public Classe(String nome){
this.nome=nome;
this.gliAlunni=new HashSet<Alunno>();
}
public String getNome(){
return this.nome;
}
public void addAlunno(Alunno al){
this.gliAlunni.add(al);
}
public Set<Alunno> getAlunni(){
Set<Alunno> ris=new HashSet<Alunno>();
ris.addAll(this.gliAlunni);
return ris;
}
}
vedrai che essa ha un metodo chiamato 'addAlunno' che prende in ingresso un singolo Alunno e lo inserisce nella collezione di tipo Set che dichiara al suo interno, tramite il metodo 'add' di Set (in realtà implementato in HashSet dato che è questa l'implementazione che viene istanziata e usata mediante l'interfaccia Set).
Quindi, come detto prima, è HashSet che al suo interno si preoccupa dei dettagli.
morskott
18-06-2009, 17:36
Se poi hai proprio necessità di accedere all'i-esimo elemento di Alunno o Classe invece di usare un Set (instanziandolo con un HashSet) puoi usare un List (che si instanzia con un ArrayList o con un LinkedList) e usare il metodo "get(i)" dove i è l'indice che vuoi accedere. Se vuoi invece fare un insieme ordinato userai invece un "SortedSet" (con implementazione TreeSet) a cui o passi oggetti di tipo "Comparable" (in pratica devi far implementare l'interfaccia Comparable agli oggetti che inserisci nell'insieme) o passandogli un oggetto "Comparator", o meglio la tua implementazione. Leggendo la javadoc sotto il package java.util sarà molto più chiaro.
Ricordati che java è case sensitive, nel senso che "classe" è diverso da "Classe", nel mio codice quando ho fatto "classe.addAlunno(alunno)" invocavo sull'oggetto puntato dalla variabile "classe" il metodo "addAlunno", non mi riferivo al nome della classe, che è "Classe".
InsomNia_Italy
18-06-2009, 19:10
Siete stati precisissimi. Ho capito bene il funzionamento e vi ringrazio.
Ho anche fatto un'altro programmino simile, tanto per vedere se avevo capito il meccanismo e funziona alla grande :) Invece di avere SCUOLA -> CLASSI -> TOT alunni per classe ho fatto RUBRICA -> NOMINATIVI -> TOT numeri di cellulare per nominativo :)
Ora mi cimento nell'aggiunta del modifica e del rimuovi. Vediamo come va :read:
InsomNia_Italy
19-06-2009, 19:22
Mi perdo in un bicchiere d'acqua. Ho problemi anche con il remove dannazzione, eppure mi posiziono correttamente e se provo ad utilizzare il metodo CONTAINS mi dice che l'oggetto che intendo eliminare esiste!
public void RimuoviNominativo(){
Scanner scanner = new Scanner(System.in);
System.out.print("Inserire COGNOME NOME del nominativo da rimuovere: ");
String acquisizione = scanner.nextLine();
StringTokenizer tk = new StringTokenizer(acquisizione);
String cognome = tk.nextToken();
String nome = tk.nextToken();
Set<NOMINATIVO> nominativo = this.rubricacell.getNominativi();
for (NOMINATIVO nomattuale:nominativo){
if (nomattuale.getCognome().equals(cognome) && nomattuale.getNome().equals(nome)) {
nominativo.remove(nomattuale);
}
}
}
Con la modifica invece nessun problema, sono riuscito a farla.
InsomNia_Italy
19-06-2009, 19:38
Come non detto :) Ho trovato l'errore e sono riuscito a fare anche il rimuovi :)
morskott
19-06-2009, 20:03
quà entra in gioco il metodo "equals", se noti la classe Object ha un metodo equals che essendo (la classe Object) la radice di tutte le classi in java è ereditato da tutte le classi che crei, esso (il metodo) dice se un oggetto è o no uguale ad un altro, se non fai overriding di equals l'oggetto sul quale lo invochi ti dice se lui ha lo stesso indirizzo di memoria dell'oggetto che gli passi come parametro. Ipotizzo che la tua classe sia class Nominativo{
private String nome;
private String cognome;
}
Tu vuoi che un "Nominativo" sia uguale ad un altro quando sono uguali il nome ed il cognome, quindi il tuo metodo equals saràpublic boolean equals(Object o){
if (o!=null && this.getClass().equals(o.getClass())){ //riga 1
Nominativo n=(Nominativo)o; //riga 2
return this.nome.equals(n.nome) && this.cognome.equals(n.cognome); //riga 3
}else{
return false; //riga 4
}
}
Analizziamo la riga 1, per non esser falso tu imponi che il parametro sia diverso da null (gli passi realmente qualcosa) e che la classe del parametro sia uguale alla tua (così Mela sarà sempre diverso da Pera). Se così non è (gli hai passato null o gli hai passato un oggetto di classe diversa) passi alla riga 4 che torna subito false.
Passando alla riga 2 tu dici a questo punto che il parametro è un Nominativo.
Finalmente alla riga 3 dici che i 2 nominativi sono uguali (l'oggetto di invocazione e il parametro) se e solo se sono uguali il nome E il cognome.
(Adesso forse non lo capirai, ma quando fai overriding di equals sei obbligata a farlo pure di hashCode, e sugli stessi parametri sui quali hai fatto l'equals, ciò si traduce inpublic int hashCode(){
return this.nome.hashCode()+31*this.cognome.hashCode();
})
In questo modo la tua classe diventa class Nominativo{
private String nome;
private String cognome;
public boolean equals(Object o){
if (o!=null && this.getClass().equals(o.getClass())){ //riga 1
Nominativo n=(Nominativo)o; //riga 2
return this.nome.equals(n.nome) && this.cognome.equals(n.cognome); //riga 3
}else{
return false; //riga 4
}
}
public int hashCode(){
return this.nome.hashCode()+31*this.cognome.hashCode();
}
}
Mo ti starai chiedendo perchè ho scritto sta manfrina, semplice, in questo modo il remove diventapublic void RimuoviNominativo(){
Scanner scanner = new Scanner(System.in);
System.out.print("Inserire COGNOME NOME del nominativo da rimuovere: ");
String acquisizione = scanner.nextLine();
StringTokenizer tk = new StringTokenizer(acquisizione);
String cognome = tk.nextToken();
String nome = tk.nextToken();
Set<NOMINATIVO> nominativo = this.rubricacell.getNominativi();
nominativo.remove(new Nominativo(nome,cognome));
}
Un altro modo per farlo senza fare overriding sarebbepublic void RimuoviNominativo(){
Scanner scanner = new Scanner(System.in);
System.out.print("Inserire COGNOME NOME del nominativo da rimuovere: ");
String acquisizione = scanner.nextLine();
StringTokenizer tk = new StringTokenizer(acquisizione);
String cognome = tk.nextToken();
String nome = tk.nextToken();
Set<NOMINATIVO> nominativo = this.rubricacell.getNominativi();
NOMINATIVO toDel=null;
for (NOMINATIVO nomattuale:nominativo){
if (nomattuale.getCognome().equals(cognome) && nomattuale.getNome().equals(nome)) {
toDel=nomattuale;
}
}
nominativo.remove(toDel);
}
PS: I nomi delle classi in java per convenzione seguono il Camel Case, cioè iniziali maiuscole ed il resto minuscolo, cioè Alunno, PrimaClasse, TestTerzaClasse etc etc, essendo solo una convenzione non sei obbligato a seguirla, solo caldamente consigliato
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.