Java/Array: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
cambio avanzamento al 50%
riorganizzo, aggiungo, taglio
Riga 1:
{{Java/Prima parte}}
 
In Java, gli array sono [[Java/Oggetti|oggetti]]. Ogni array è dotato di un numero fisso di ''celle'', dette anche ''slot'' (in inglese), ognuna delle quali è identificata da un intero positivo, chiamato "indice". Il numero esatto di ''slot'' viene indicato al momento della allocazione dell'array in memoria.
== Concetto ==
In Java, gli array sono [[Java/Oggetti|oggetti]]. Ogni array è dotato di un numero prefissato di ''celle'', dette anche ''slot'' (in inglese), ognuna delle quali ha un proprio numero identificativo, chiamato "indice". Il numero esatto viene indicato al momento della creazione dell'array in memoria.
 
Il capito dedicato agli array nella seconda edizione delle specifiche di linguaggio è il [http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html capitolo 10].
 
__TOC__
== Creazione ==
Per dichiarare e inizializzare una variabile di tipo array si usa la seguente sintassi:
<source lang="Java">
byte[] array = new byte[1024];
</source>
 
== Dichiarazione ==
Questa istruzione può essere separata in due parti:
Il tipo di un array è identificato dal nome del ''component type'', seguito da una coppia di parentesi quadre. Esempi:
<source lang="Java">
*<tt>int[]</tt> indica il tipo <tt>array di int</tt>
byte[] array;
*<tt>Object[]</tt> indica il tipo <tt>array di Object</tt>
array = new byte[1024];
*<tt>int[][]</tt> indica il tipo array il cui ''component type'' è <tt>int[]</tt>, quindi, in definitiva, indica il tipo <tt>array di array di int</tt>
</source>
 
Il tipo di un array non include '''mai''' il numero degli elementi (a differenza di quanto avviene in C e in C++).
Si può accedere alle celle dell'array tramite la solita sintassi che fa uso di parentesi quadre:
<source lang="Java">
array[0] = 64;
System.out.println( array[0] );
</source>
 
== Creazione e distruzione ==
=== Spiegazione ===
; Con inizializzazione al valore di default
''Nota: questo paragrafo è destinato a chi ha già dimestichezza con il concetto di ''[[Java/Oggetti#Oggetti e reference|reference]]''.''
È possibile allocare un array in memoria servendosi della parola-chiave <tt>new</tt>:
:<tt>int[] i = new int[10];</tt>
Il numero di elementi tra parentesi quadre è obbligatorio.
 
Tutte le celle dell'array sono automaticamente [[Java/Oggetti#Inizializzazione dei campi|inizializzate]] con il valore di default del ''component type'' corrispondente. Nell'esempio appena mostrato, tutti gli ''slot'' dell'array referenziato dalla variabile <tt>i</tt> valgono inizialmente <tt>0</tt>.
<source lang="Java">
byte[] array;
</source>
In realtà, questa riga non alloca alcun array in memoria, ma si limita a dichiarare una variabile che può ''ospitare'' il reference di un array - se e quando ne sarà creato uno. Eccetto che per il tipo, quella dichiarata è una "normale" [[Java/Variabili|variabile]] che non può essere usata se prima non viene inizializzata:
<source lang="Java">
byte[] array;
// array[0] = 5; // non compila
</source>
 
Ad esempio, l'istruzione <code>new byte[1024]</code> crea un array di 1024 slot inizializzati al valore 0; oppure <code>new Object[1024]</code> crea un array di 1024 celle e assegna loro il valore ''null''. Si noti che questo meccanismo è diverso da quello che si trova in altri linguaggi, come il C (in cui le celle dell'array hanno inizialmente valori casuali o imprevedibili), ed è lo stesso meccanismo che in Java entra in atto quando si crea un oggetto di qualunque altro tipo.
 
Ad allocare la memoria provvede l'operatore <tt>new</tt>, che restituisce il ''reference'' dell'array allocato. Ad esempio, la riga seguente dichiara una variabile di tipo ''array di byte'', crea un array di 1024 celle in memoria, e ne copia il ''reference'' nella variabile dichiarata:
<source lang="Java">
byte[] array = new byte[1024];
</source>
 
Queste sono tre operazioni distinte ed è possibile separarle:
<source lang="Java">
byte[] array; // dichiarazione variabile
array = new byte[1024]; // alloco array e copio reference
</source>
 
; Indicando i singoli elementi
=== Alternative ===
È disponibile un costrutto alternativo che permette di indicare direttamente i valori delle singole celle:
<source lang="Java">
Line 62 ⟶ 41:
</source>
 
Ritornando all'esempio precedente, unUn'altra forma equivalente e più concisa è
<source lang="Java">
int[] numeri = { -1, 0, 0 };
Line 74 ⟶ 53:
perché la dichiarazione e l'inizializzazione della variabile <tt>numeri</tt> ora sono due istruzioni diverse.
 
== Iterazione ==
''Iterare'' lungo un array significa scorrerlo cella per cella ed eseguire determinate operazioni man mano che lo si scorre.
 
; Deallocazione
Questo è possibile perché ogni cella ha un ''indice'' univoco che la distingue dalle altre. La prima cella ha sempre indice <tt>0</tt>, quindi l'ultima ha, ovviamente, indice <tt>n - 1</tt> dove <tt>n</tt> è la lunghezza dell'array.<ref>In gergo si dice che in Java gli array sono ''0-based''; altri linguaggi hanno array ''1-based'' e altri ancora permettono di definire intervalli arbitrari per gli indici.</ref>
A differenza di quanto avviene in C++, gli array '''non''' vengono distrutti esplicitamente, in quanto il Java è dotato di [[w:it:garbage collector|garbage collector]].
 
== Tipi array ==
Il modo più intuitivo per iterare lungo un array è usare una variabile numerica, chiamata ''indice'' o ''variabile contatore'', farla partire da <tt>0</tt> e incrementarla di uno fino ad arrivare all'indice massimo. Se si scrivono delle istruzioni che lavorano su un generico indice ''i'', si può mettere insieme il tutto in un ciclo ''for''.
I tipi array sono tipi riferimento.
 
Come per tutti i tipi riferimento, il valore di default per un campo di tipo array non inizializzato è <tt>null</tt>:
<source lang="Java">
class C {
private final int[] array;
public static void main(String[] args) {
C c = new C();
for(int i = 0; i < array.length; i++) {
System.out.println(i); // stampa a video il valore 0
}
}
}
</source>
 
=== Gerarchia delle classi ===
È sempre possibile convertire un tipo array verso il tipo <tt>Object</tt> tramite cast implicito, in quanto tutti gli array sono oggetti.
 
In aggiunta, tutti gli array possono essere convertiti verso i tipi [http://download.oracle.com/javase/6/docs/api/java/lang/Cloneable.html java.lang.Cloneable] e [http://download.oracle.com/javase/6/docs/api/java/io/Serializable.html java.io.Serializable]. In particolare,
*gli array supportano il metodo <code>[http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#clone() clone()]</code>;
*è possibile serializzare gli array come qualunque altro oggetto:
<source lang="Java">
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("un_file.ser"));
oos.writeObject(unArray);
</source>
 
=== Gerarchia fra tipi array ===
Il tipo di un array creato con <tt>new T[...]</tt> è <tt>T[]</tt>. L'array può essere convertito verso qualunque tipo <code>S[]</tt> dove <tt>S</tt> è un supertipo di <tt>T</tt>.
 
Questo significa che tutti gli array di oggetti possono essere convertiti verso <code>Object[]</code>.
 
 
== Membri di un array ==
; Celle
Le singole celle dell'array sono considerate come dei campi, e sono identificate apponendo una coppia di parentesi quadre ad un'espressione il cui ''compile-time type'' sia un tipo array, e inserendo fra queste parentesi un'espressione il cui ''compile-time type'' sia convertibile verso il tipo <tt>int</tt> tramite cast implicito.
 
Ad esempio:
:<tt>System.out.println(i[0]);</tt> stampa a video il valore della prima cella dell'array referenziato dalla variabile <tt>i</tt>.
:<tt>i[0] = 5;</tt> assegna il valore intero <tt>5</tt> alla prima cella dell'array.
 
L'indice della prima cella è sempre <tt>0</tt><ref>Si dice che gli indici sono <tt>0-based</tt>. In altri linguaggi, gli indici sono sempre <tt>1-based</tt> o possono essere scelti arbitrariamente.</ref> e, pertanto, l'indice dell'ultima cella è sempre <tt>n - 1</tt>, dove <tt>n</tt> è il numero di celle totali.
 
; Lunghezza
Il numero di celle è restituito dal campo <tt>length</tt>. Questo si comporta come un campo <tt>final int</tt>.
 
; Clonazione
Gli array esibiscono un metodo pubblico <tt>[http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#clone() clone()]</tt>.
 
== ArrayIndexOutOfBoundsException ==
A differenza di quanto avviene in altri linguaggi (come il C) in Java non è permesso leggere o scrivere al di fuori della memoria che è stata allocata per l'array. In altre parole, in Java 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>).
 
Se si tenta di compiere una operazione del genere, la macchina virtuale lancerà una eccezione a tempo di esecuzione:
<source lang="Java">
int[] array = new int[3];
array[-1] = 10; // ops...
</source>
 
L'eccezione lanciata è sempre di tipo [http://download.oracle.com/javase/6/docs/api/java/lang/ArrayIndexOutOfBoundsException.html ArrayIndexOutOfBoundsException]. Il [[Java/Gestione delle eccezioni|meccanismo che entra in gioco]] quando si verifica un caso del genere è del tutto analogo a quello che si verifica quando viene lanciata un'eccezione di altro tipo.
 
== Utilizzi tipici ==
=== Iterazione classica ===
 
=== Ciclo ''for'' ===
<source lang="Java">
// Riempie l'array con i numeri progressivi da 0 ad array.length:
Line 93 ⟶ 134:
*quindi, la condizione da applicare al ciclo è <code>i <= array.length-1</code>, oppure, equivalentemente, <code>i < array.length</code>.
 
===; Un errore comune ===
Molti programmatori alle prime armi con il Java commettono il seguente errore:
<source lang="Java">
Line 99 ⟶ 140:
... // istruzioni
</source>
Questo ciclo fa sì che le istruzioni che costituiscono il corpo del ''for'' siano eseguite una volta in più rispetto a quanto avviene nel codice precedente, perché il corpo viene eseguito anche per <code>i = array.length</code>, cioè quando ''i'' rappresenta un indice che non ha una cella corrispondente nell'array. Un simile errore viene scoperto solo a ''run-time'', quando il programma [[#ArrayIndexOutOfBoundsException|genera una ArrayIndexOutOfBoundsException]] non prevista (vedere [[#ArrayIndexOutOfBoundsException|più giù]]).
 
 
=== Ciclo ''enhanced for'' ===
=== For each ===
A volte si può usare un costrutto alternativo:
<source lang="Java">
Line 117 ⟶ 159:
ovvero scorre l'array, dall'indice 0 all'indice <code>array.length - 1</code>, assegnando automaticamente il valore <code>array[i]</code> alla variabile <code>slot</code>, e ad ogni ciclo esegue l'istruzione <code>System.out.println(slot)</code>.
 
SiÈ trattachiamato di''for each'' o ''enhanced for'' ed è un costrutto introdotto dalla versione 1.5 di Java<ref>Terza eedizione della Java Language Specification.</ref>, che risparmia al programmatore il calcolo a mente degli indici se questi non sono realmente necessari (calcolo che viene svolto in automatico dal compilatore). Lo svantaggio è che non si può usare sempre, ad esempio se bisogna accedere alle celle dell'array in scrittura o se è necessario accedere a più di una cella alla volta.
 
== Altre info ==
; Inizializzazione delle celle dell'array
Si noti che, quando viene creato un array tramite ''new'', tutti gli ''slot'' vengono automaticamente [[Java/Oggetti#Inizializzazione dei campi|inizializzati]] al valore di default del tipo corrispondente. Ad esempio, l'istruzione <code>new byte[1024]</code> crea un array di 1024 slot inizializzati al valore 0; oppure <code>new Object[1024]</code> crea un array di 1024 celle e assegna loro il valore ''null''. Si noti che questo meccanismo è diverso da quello che si trova in altri linguaggi, come il C (in cui le celle dell'array hanno inizialmente valori casuali o imprevedibili) ed è lo stesso meccanismo che in Java entra in atto quando si crea un oggetto di qualunque altro tipo.
 
== Array e collezioni ==
; Lunghezza dell'array
Le librerie standard della piattaforma Java forniscono un insieme di classi e interfacce che definiscono collezioni, e che si chiama ''Java Collections Framework''.
A differenza di quanto avviene in altri linguaggi, in java gli array '''non''' possono essere ridimensionati:
<source lang="Java">
int[] array = new int[0];
// array.length = 5; // non compila
</source>
Le dimensioni di un array restano costanti fin dal momento della sua creazione. D'altra parte, si può sempre assegnare alla variabile un array diverso:
<source lang="Java">
int[] array = new int[0];
array = new int[5]; // ok
</source>
 
=== Conversione ===
Questo è possibile perché
; Da collezione ad array
*è vero che il primo array creato ha dimensione <code>0</code> e che questa dimensione non può cambiare,
Invocare sulla collezione uno dei due metodi <tt>[http://download.oracle.com/javase/6/docs/api/java/util/Collection.html toArray()]</tt>.
*ma è anche vero che la variabile <code>array</code> è una normale variabile non ''final'', e, in quanto tale, ammette la possibilità che vi sia inserito un reference ad un ''nuovo'' array, diverso dal primo, e, quindi, di dimensione diversa.
'''''Nota''': questo metodo restituisce una '''copia''' degli elementi della collezione: se quest'ultima viene modificata in seguito, le modifiche non interesseranno anche l'array.''
 
==; TipiDa array ==a collezione
Invocare il metodo <tt>[http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html#asList(T...) java.util.Arrays.asList()]</tt>.
Il tipo di un array creato con <code>new T[...]</code> è <code>T[]</code>. L'array può essere convertito verso qualunque tipo <code>S[]</code> dove <code>S</code> è un supertipo di <code>T</code>.
'''''Nota''': questo metodo restituisce una List che opera '''sull'array''' passato come argomento: se quest'ultimo verrà modificato in seguito, le modifiche potrebbero ripercuotersi sulla List.''
 
Questo significa che tutti gli array di oggetti (cioè gli array in cui il tipo <code>T</code> è una classe o interfaccia) possono essere convertiti verso <code>Object[]</code>. Inoltre, poiché tutti gli array sono oggetti, possono essere convertiti anche verso <code>Object</code>.
 
Infine, tutti gli array possono essere convertiti verso i tipi [http://download.oracle.com/javase/6/docs/api/java/lang/Cloneable.html java.lang.Cloneable] e [http://download.oracle.com/javase/6/docs/api/java/io/Serializable.html java.io.Serializable]. In particolare,
*gli array supportano il metodo <code>[http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#clone() clone()]</code>;
*è possibile serializzare gli array come qualunque altro oggetto:
<source lang="Java">
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("unfile"));
oos.writeObject(unArray);
</source>
 
== Array e Collection ==
{{vedi anche|Java/Collections{{!}}Java Collections Framework}}
Un array puòha esserela consideratostessa comefunzionalità di una [http://download.oracle.com/javase/6/docs/api/java/util/List.html java.util.List] di dimensioni costanti e che supporta le operazioni di lettura e scrittura degli elementi.
 
La scelta fra un tipo array e una List (o altra Collection) è arbitraria e lasciata al programmatore.
Line 161 ⟶ 184:
 
Nella scelta si deve tenere conto anche del fatto che List è un'interfaccia, quindi un client può implementare una propria versione di List che esegua codice personalizzato in risposta all'invocazione di alcuni dei suoi metodi. Ad esempio, un'implementazione può gestire una coda di [http://download.oracle.com/javase/6/docs/api/java/util/EventListener.html java.util.EventListener]s notificati ogni volta che la lista subisce un cambiamento; oppure si possono adottare alcune delle implementazioni fornite dalla classe [http://download.oracle.com/javase/6/docs/api/java/util/Collections.html java.util.Collections]; ecc. Insomma, lo strato di astrazione fornito dall'interfaccia List permette di riutilizzare il codice, se in futuro dovessero presentarsi nuove esigenze da parte di qualche client, sfruttando un "punto di accesso" tramite il quale si possono inserire delle implementazioni personalizzate della propria lista con una modifica minima al codice originale<ref>Anzi, se il codice è stato scritto bene, non è necessario modificare il codice originale, ma solo il client, e anche in quest'ultimo, nel migliore dei casi, è sufficiente modificare una sola riga di codice</ref>. Questo non è possibile se si usano gli arrays.
 
== ArrayIndexOutOfBoundsException ==
{{vedi anche|Java/Gestione delle eccezioni{{!}}Gestione delle eccezioni}}
A differenza di quanto avviene in altri linguaggi (come il C) in Java non è permesso leggere o scrivere al di fuori della memoria che è stata allocata per l'array. In altre parole, in Java 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>).
 
Se si tenta di compiere una operazione del genere, la macchina virtuale lancerà una eccezione a tempo di esecuzione:
<source lang="Java">
int[] array = new int[3];
array[-1] = 10; // ops...
</source>
 
L'eccezione lanciata è sempre di tipo [http://download.oracle.com/javase/6/docs/api/java/lang/ArrayIndexOutOfBoundsException.html ArrayIndexOutOfBoundsException]. Il [[Java/Gestione delle eccezioni|meccanismo che entra in gioco]] quando si verifica un caso del genere è del tutto analogo a quello che si verifica quando viene lanciata un'eccezione di altro tipo.
 
== Note ==