Newsgroup: it.comp.java
Titolo: Array di oggetti contenente un array

Mi sono appena accorto di un problema.
Ho un oggetto tra i cui attributi vi è un array di integer.
Se provo ad instanziare un array di questi oggetti, quando vado a
riempire gli array di ogni singolo oggetto mi accorgo che in pratica
questo array è uguale per tutti gli oggetti, come se si trattasse di un
unico oggetto array al quale fanno riferimento tutti i miei oggetti.
E' corretto questo comportamento?
THanks
LuKe


Decisamente no.
Possono essere accadute due cose:
1) l'attributo contenente l'array e' statico. Questo significa che tutti 
gli oggetti di quella classe condividono l'attributo.
2) In realta' in java non esistono array di oggetti ma solo array di 
riferimenti. Puo' darsi che tutti gli elementi dell'array siano 
riferimenti allo stesso oggetto.
Se non trovi il problema posta la dichiarazione della classe e 
l'inizializzazione dell'array.
Andrea Polci

 
Grazie per la risposta.
Ad occhio il problema è del secondo tipo. Non riesco però a capire come 
risolverlo.
Invio la definizione della classe e l'inizializzazione dell'array:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
public class Student{
     private String name;
     private int[] grades = new int[5];
     private double average;
     public Student(String theName, int[] theGrades){
         name = theName;
         grades = theGrades;
         average = 0;
     }
     public String toString(){
     //calculateAverage();
         String description =  name + "\t";
         for (int i = 0; i < 5; i++)
             description += grades[1] + "\t";
         description += average;
         return description;
     }
     public void calculateAverage(){
         average = 0;
         for (int i = 0; i < 5; i++)
             average += grades[i];
         average /= 5;
     }
     public double getAverage(){
         return average;
     }
}
////////////////////////////////
    for (int i = 0;i < 2 ;i++){
         line = Keyboard.readString();
         tokenizer = new StringTokenizer(line);
         if (tokenizer.countTokens() != 6)
             System.out.println("ERROR");
         else{
             name = tokenizer.nextToken();
             for (int y = 0; y < 5; y++)
                 theGrades[y] = Integer.parseInt(tokenizer.nextToken());
             }
             list[i] = new Student(name, theGrades);
         }// for
^^^^^^^^^^^^^^^^^
Thanks

 risolverlo.
E invece e' di un terzo tipo che non avevo immaginato ;-)
tu dichiari grades nel seguente modo:
 >     private int[] grades = new int[5];
Pero' poi nel costruttore fai
 >         grades = theGrades;
Questo non fa altro che buttare alle ortiche il vecchio valore di grades 
e assegnare alla variabile lo stesso valore di theGrades.
Ricordati che in Java gli array sono oggetti (anche se di un tipo 
particolare) e quindi grades e theGrades sono riferimenti ad oggetti di 
tipo array.
Ad ogni iterazione costruisci correttamente un nuovo oggetto di Classe 
Student:
 >             list[i] = new Student(name, theGrades);
Pero' commetti l'errore di utilizzare ad ogni iterazione lo stesso array 
theGrades.
Alla seconda iterazione, ad esempio, cambiando gli elementi di theGrades 
cambi anche gli elementi di list[0].grades poiche essi sono due 
riferimenti allo stesso oggetto (theGrades == list[0].grades).
Alla fine dell'iterazione avrai: theGrades == list[0].grades == 
list[1].grades
Un modo veloce per correggere questo comportamento e' aggiungere una 
riga passando da:
 >             name = tokenizer.nextToken();
 >             for (int y = 0; y < 5; y++)
a:
 >             name = tokenizer.nextToken();
 >             theGrades = new int[5];
 >             for (int y = 0; y < 5; y++)
Questo fa si che ad ogni iterazione tu utilizzi un nuovo array.
Andrea Polci

Grazie Andrea,
avevi proprio ragione!!!!!!!
Adesso funziona
THanks
LuKe

  >             for (int y = 0; y < 5; y++)
Veramente secondo me il modo piu' corretto è fare una "defensive copy" nel
costruttore. Un costrutture del genere si affida alla correttezza del
codice del client che non è mai una grande idea ;)
qualcosa del genere:
public Student(String theName, int[] theGrades){
/*qui bisogna mettere un po' di controlli sull'input.
ad esempio non credo che un nome null o di lunghezza 0 sia
utile */
   if(theName == null || theName.length()==0)
      throw new IllegalArgumentException ("nome vuoto");
   if(theGrades.length != grades.length)
      throw new IllegalArgumentException ("lunghezza array: "+
          theGrades.length+". Dovrebbe essere: "+grades.length);
   //qui i parametri sono corretti
   name = theName;
   grades = System.arrayCopy(theGrades,0,grades,0,grades.length);
   average = 0;
}
dovrebbe andare.
Ciao
Matteo
-- 
chi sono e soprattutto chi non sono:
http://www.ilnomedeldominio.it
un piccolo programma per studenti universitari:
http://inutility.ilnomedeldominio.it/imsv/

 codice del client che non č mai una grande idea ;)
Perfettamente daccordo sul fatto che la tua soluzione sia piu' corretta,
infatti io avevo solo suggerito un modo ***veloce*** per
correggere l'errore.
Anche se bisogna sempre vedere il contesto, se si tratta di un array di
5 elementi come in questo caso e' un conto, ma se si parla di array di
dimensione non definita (magari centinaia o migliaia di elementi)
bisogna pensarci molto bene prima di fare copie.
Andrea
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 bisogna pensarci molto bene prima di fare copie.
Beh anche quella che proponevi è una copia:
name = tokenizer.nextToken();
theGrades = new int[5];
for (int y = 0; y < 5; y++)
Si puo' pensare di non effettuare copie solo se il contesto è sotto il
controllo di chi scrive la classe server e garantisce che l'array non sarà
modificato.
Ma non è questo il caso visto che viene modificato e poi le modifiche si
ripercuotono ovunque.


 }
Se posso permettermi, sarebbe meglio prima fare la copia e poi controllare se i 
valori sono validi; cosi facendo ci si mette al riparo da eventuali modifiche 
che potrebbero occorrere durante la "window of vulnerability"(ossia quel periodo 
di tempo fra il controllo dei valori e la copia difensiva) da parte di un'altra 
thread.
Marco
-- 
reply: remove duh.spam.
http://javac.imap.cc

un'altra thread.
Dobbiamo aver studiato sullo stesso testo :)
In questo caso credo che non ci sia bisogno perché i controlli vengono fatti
su String che sono oggetti immutabili quindi nessun altro thread li può
modificare e _lunghezza_ dell'array, che come sai non puo' cambiare.
Quindi non serve e se non serve direi che è meglio evitarla perché se uno di
quei due controlli lanciasse un eccezione (e a patto di mettere new int[5]
nel costruttore e quindi grades.length con un numero) ci si risparmierebbe
la creazione dell'array.


quindi grades.length con un numero
mi sono mangiato una parola, era:
e quindi sostituire grades.length con un numero


 In questo caso credo che non ci sia bisogno 
Si hai ragione, in questo caso la mia osservazione non è molto pertinente... %-)
Dovrei smetterla di leggere i post in maniera sintetica("defensive copy"....qui 
bisogna mettere un po' di controlli sull'input.....System.arrayCopy... :)
ciau
