Java/Array: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
mNessun oggetto della modifica
Pietrodn (discussione | contributi)
integro con testo da w:Array in Java
Riga 1:
{{Java/Seconda parte}}
 
Nel [[w:linguaggio di programmazione|linguaggio di programmazione]] [[w:Programmazione orientata agli oggetti|ad oggetti]] Java, gli '''array''' sono [[w:struttura dati|strutture dati]] costituite dall'aggregazione di un prefissato numero di [[variabile (informatica)|variabili]], individualmente accessibili tramite un indice numerico.
Un array rappresenta una sequenza finita di elementi che hanno uno stesso tipo in comune. Il relativo capitolo, nella seconda edizione della specifica di linguaggio, è il capitolo 10.
 
Un array può essere immaginato come un casellario costituito da un certo numero di celle. Le celle si comportano individualmente come variabili tradizionali (ovvero possono essere assegnate, lette, e così via). Tutte le celle di un array sono variabili dello stesso tipo, detto ''tipo degli elementi dell'array'' (''element type'' in [[inglese]]). In Java, gli array sono [[w:oggetto (informatica)|oggetti]].
 
__TOC__
Line 74 ⟶ 76:
 
== Tipi array ==
=== Gli array come oggetti ===
 
In Java, gli array sono oggetti<ref>{{cita web|url=http://java.sun.com/docs/books/jls/third_edition/html/arrays.html|titolo=The Java Language Specification, Third Edition, ''Arrays''|accesso=21 aprile 2011}}</ref><ref>{{cita web|url=http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.3.1|titolo=The Java Language Specification, Third Edition, ''Types, Values, and Variables''|accesso=6 maggio 2011}}</ref>.
 
La prima implicazione di questo fatto è che gli array si considerano dotati di tutti i metodi e gli attributi della classe <code>Object</code>. Per esempio, è possibile richiamare i metodi <code>wait()</code> o <code>notify()</code> su un array:
<source lang=java>
unArray.wait();
</source>
La seconda implicazione è che è possibile eseguire un'operazione di ''casting'' da un tipo array ad <code>Object</code> dovunque sia necessario: assegnare ad una variabile di tipo Object un ''reference'' ad un array, passare un array come argomento a un metodo o costruttore che accetta argomenti di tipo <code>Object</code>, ecc.
 
In aggiunta, gli array possono essere convertiti ai tipi <tt>Serializable</tt> e <tt>Cloneable</tt><ref>{{cita web|http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html|''The Java Language Specification, Second Edition'' - ''Arrays''|23 marzo 2011}}</ref>.
 
Così, per esempio, si può [[w:serializzazione|serializzare]] un array allo scopo di salvarlo su [[file]] nello stesso modo in cui si salva su file un qualsiasi oggetto serializzabile:
<source lang=java>
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("unfile"));
oos.writeObject(unArray);
</source>
 
Gli array sono anche dotati di un [[w:attributo (programmazione)|attributo]] specifico, denominato <code>length</code>, che indica il numero di celle che esso contiene. La presenza di questo attributo permette di passare un array tra diverse parti del programma senza dover indicare anche la sua dimensione (cosa che in altri linguaggi, come il C, è invece obbligatoria). Una variante più elegante del ciclo <code>for</code> riportato sopra potrebbe dunque essere:
<source lang=java>
for(int i=2; i<unArray.length; i++)
unArray[i] = unArray[i-1]+unArray[i-2];
</source>
Di conseguenza, eventuali modifiche alla dimensione dell'array (specificata nella riga che contiene l'operatore <code>new</code>) non costringeranno il programmatore a modificare ogni altro punto del programma in cui si fa uso dell'array.
 
=== Gerarchia delle classi ===
Line 92 ⟶ 118:
Questo significa che tutti gli array di oggetti possono essere convertiti verso <code>Object[]</code>.
 
==Utilizzo degli array==
== ArrayIndexOutOfBoundsException ==
 
Per accedere a una cella di un array, come in altri linguaggi, si utilizza una sintassi che consente di specificare l'indice (ovvero la posizione nell'array) di tale cella. Gli indici sono numeri interi consecutivi a partire da 0 (indice della prima cella). La seguente istruzione assegna il valore intero 1 alle prime due celle dell'array:
<source lang=java>
unArray[0] = 1;
unArray[1] = 1;
</source>
L'indice può essere specificato da un valore costante (come i valori 0 e 1 nell'esempio) oppure, più in generale, da una [[w:espressione (informatica)|espressione]] di valore intero. Spesso tale espressione è ricavata a partire dal valore di una variabile contatore di un ciclo <code>for</code>. L'esempio che segue prosegue la valorizzazione dell'array <code>unArray</code> riempiendolo con i primi numeri della [[numeri di Fibonacci|sequenza di Fibonacci]] (il primo e il secondo valore sono già stati assegnati sopra):
<source lang=java>
for(int i=2; i<45; i++)
unArray[i] = unArray[i-1]+unArray[i-2];
</source>
Tradotto in italiano, il frammento di codice riportato suonerebbe così: ''per tutti i valori crescenti di i da 2 a 44, assegna all'i-esima cella di <code>unArray</code> la somma dei contenuti delle due celle precedenti''.
 
==Errori di indicizzazione==
 
Un tipico errore di programmazione consiste nell'uso di indici scorretti, quindi inferiori a 0 o superiori all'indice massimo (quindi superiori a <code>unArray.length-1</code>). Nei linguaggi [[compilatore|compilati]] come il [[C (linguaggio)|C]], questo può portare a errori di accesso alla memoria. In Java, un errore di indicizzazione viene sempre rilevato a [[run-time]] dalla [[macchina virtuale Java|macchina virtuale]] e segnalato tramite una [[gestione delle eccezioni in Java|eccezione]].
 
Per esempio, il seguente frammento di codice contiene un errore comune: l'uso dell'operatore di confronto minore o uguale, invece del minore, per stabilire l'ultimo valore assunto dal contatore del ciclo.
<source lang=java>
for(int i=2; i<=45; i++)
unArray[i] = unArray[i-1]+unArray[i-2];
</source>
Questo ciclo esegue l'ultima iterazione per <code>i</code> uguale a 45. Poiché gli indici degli array Java partono da 0, l'ultima cella (cioè la centesima) ha indice <code>unArray.length-1=44</code>; il valore 45 è quindi scorretto e causerà una eccezione. L'eccezione sollevata è di classe <code>ArrayIndexOutOfBoundsException</code> (''indice dell'array fuori dagli estremi'').
 
Secondo il convenzionale meccanismo di [[gestione delle eccezioni]] in Java, a meno che questa eccezione non sia catturata da una clausola <code>try-catch</code>, essa causerà la terminazione improvvisa del metodo corrente e dei metodi che lo hanno invocato, e così via, fino a terminare il thread sul quale l'istruzione è stata eseguita. Questo comportamento è decisamente preferibile a quello del C, in cui l'errore di cui sopra non viene rilevato e comporta la scrittura di un valore in una cella di memoria esterna all'array (cella che potrebbe appartenere alla memoria allocata per un'altra variabile, che quindi muterà valore in modo imprevisto, causando un potenziale malfunzionamento molto difficile da scoprire e da [[debug|correggere]]).
 
=== ArrayIndexOutOfBoundsException ===
Non è permesso leggere o scrivere al di fuori della memoria che è stata allocata per un array. In altre parole, non è possibile accedere ad una cella che ha un indice inferiore all'indice minimo (che è sempre 0) o superiore all'indice massimo (che è sempre pari ad <code>array.length - 1</code>).
 
Line 146 ⟶ 199:
*se bisogna accedere alle celle dell'array in scrittura;
*se è necessario accedere a più di una cella alla volta.
 
 
== Array e collezioni ==
Line 169 ⟶ 221:
Se si sta progettando l'implementazione privata di una classe o il corpo di un metodo, non c'è motivo di porsi il problema, perché, in futuro, si potrà tornare indietro sulla decisione con modifiche che resteranno sempre circoscritte.
 
Negli altri casi, in genere, non vale la pena di scegliere un tipo array al posto di una collezione, se l'<nowiki/>''unica'' ragione è ottimizzare il codice che accede alle celle, cioè per usare l'accesso diretto alla memoria come "scorciatoia" che eviti le invocazioni dei metodi <code>get</code> e <code>set</code>. Infatti, le macchine virtuali odierne adottano delle tecniche di ottimizzazione (come l'<nowiki/>''inlining'' dei metodi di dimensioni ridotte) che rendono superfluo un accorgimento come questo. Inoltre, la classe {{Java/Javadoc|java.util.ArrayList|javadoc=java/util/ArrayList.html}} esibisce buone prestazioni per la maggior parte delle applicazioni in cui sia necessario disporre di una lista ad accesso casuale, e la classe {{Java/Javadoc|java.util.LinkedList|javadoc=java/util/LinkedList.html}} è sicuramente più facile da usare di un array nel caso sia necessario uno [[w:it:stack|stack]] o una [[w:it:Coda (informatica)|coda]].
 
Nella scelta si deve tenere conto anche del fatto che lo strato di astrazione aggiuntivo permette ai client di fornire una implementazione personalizzata, e ciò rende la struttura a oggetti più resistente nei confronti delle eventuali modifiche future che potrà essere necessario implementare nel programma.<br/>
Line 175 ⟶ 227:
<ref group="A">Vedi anche: [http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#nCopies(int,%20T) documentazione del metodo <tt>java.util.Collections.nCopies()</tt>]</ref>
Un'altra implementazione può accedere direttamente alle proprietà di un oggetto o ai campi di un database, mascherandolo dietro l'interfaccia della collezione, invece di utilizzare la memoria come passaggio intermedio (e obbligatorio) per la memorizzazione dei dati.<br/>
Inoltre, per manipolare il contenuto di un array, riordinandolo o trasformando i singoli elementi, è necessario portare il programma ad eseguire costose iterazioni, ed eventualmente duplicarne il contenuto in memoria finché la trasformazione non è completa. Una collezione che sia stata implementata come [[w:it:wrapper|wrapper]], al contrario, può svolgere queste operazioni "al volo" e solo sugli elementi per i quali è effettivamente richiesta a tempo di esecuzione, lasciando inalterata la collezione iniziale.
 
==Array di oggetti==
 
Gli esempi di codice riportati fin qui creano e manipolano un array del [[w:tipo primitivo|tipo primitivo]] ''int''. È possibile creare array di qualsiasi altro tipo, inclusi ovviamente i tipi riferimento (quindi le classi, le interfacce e perfino gli array). Il seguente frammento di codice dichiara un reference a un array con tipo base ''String'' e crea l'array con l'operatore ''new'':
<source lang=java>
String altroArray[] = new String[100];
</source>
Il funzionamento dell'array è identico rispetto a quello di <code>unArray</code>. Si deve comunque ricordare che un array può essere equiparato a un casellario costituito da N celle del tipo base. Ne consegue che le celle di <code>altroArray</code> si comportano come variabili di tipo <code>String</code>. Di conseguenza, come avviene per una variabile che ha tipo riferimento, tecnicamente le celle contengono solo ''reference'' a oggetti e non gli oggetti stessi.
 
Un esempio di codice che riempie le celle dell'array:
<source lang=java>
for(int i = 0; i < altroArray.length; i++)
altroArray[i] = "Stringa numero " + i;
</source>
 
==Matrici e array multidimensionali==
 
Negli array multidimensionali, una cella non è identificata da un singolo valore di indice ma da una N-upla di indici. Per visualizzare il concetto, si pensi al caso di un array bidimensionale (detto anche '''matrice'''), che può essere immaginato come una tabella costituita da righe e colonne. In tal caso le celle saranno identificate da due indici (numero di riga e numero di colonna).
 
In Java, come nella tradizione [[C]], gli array multidimensionali non sono altro che ''array di array''. La sintassi e la semantica seguono da questa equivalenza (sebbene questa visione non sia necessariamente la più semplice da afferrare per un neofita).
 
Per dichiarare un array a più dimensioni (per esempio 2), la sintassi è come segue:
<source lang=java>
int[][] tabelline;
</source>
La sintassi, in effetti, dichiara <code>tabelline</code> come un array i cui elementi sono array di tipo <code>int[]</code>.
 
Si può allocare la matrice con una istruzione ''new'' della seguente forma:
<source lang=java>
tabelline = new int[10][10];
</source>
Questa istruzione crea una "matrice rettangolare" NxM (nella fattispecie, quadrata, 10x10). Così come gli array sono spesso manipolati tramite un "ciclo for", per le matrici N-dimensionali è frequente l'accesso tramite N cicli for "annidati". Due cicli annidati si comportano come le lancette dell'orologio: a ogni "step" (o iterazione) del ciclo più esterno (lancetta delle ore) il ciclo più interno esegue interamente il proprio percorso (lancetta dei minuti). Il seguente frammento di codice valorizza l'array "tabelline" inserendoci la [[w:tavola pitagorica|tavola pitagorica]]:
<source lang=java>
for(int i=0; i<10; i++)
for(int j=0; j<10; j++)
tabelline[i][j] = (i+1)*(j+1);
</source>
La creazione di una matrice di interi come <code>tabelline</code> può essere anche spezzata in due passaggi: prima si crea un array di array di interi, dopodiché si assegna ad ogni cella di detto array il reference a un array di interi:
<source lang=java>
tabelline = new int[10][];
tabelline[0] = new int[10];
tabelline[1] = new int[10];
...
</source>
Questo secondo approccio si può "leggere" in questi termini: la prima istruzione stabilisce quante saranno le ''righe'' della matrice; le successive specificano il numero di colonne di ogni riga. Quest'ultimo approccio è più flessibile del precedente, perché permette di avere righe di diversa lunghezza. Una "matrice triangolare" potrebbe per esempio essere creata come segue:
<source lang=java>
tabelline = new int[10][];
for(int i=0; i<tabelline.length; i++)
tabelline[i] = new int[i+1];
</source>
 
== Differenze con il C++ ==
Line 203 ⟶ 305:
; Approfondimenti
<references group="A"/>
 
 
[[Categoria:Java|Array]]