Java/Array: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Gian BOT (discussione | contributi)
m Bot: sostituzione tag obsoleti
Riga 10:
Le caratteristiche degli array sono definite dalla specifica di linguaggio.
 
Un array è un [[Java/Oggetti|oggetto]] dotato di un numero fisso di ''celle'' (in inglese, ''slot''), il tipo delle quali è chiamato ''component type'' dell'array. Esse si comportano esattamente come se fossero dei campi non <ttcode>final</ttcode>, con le seguenti differenze:
*invece che da un nome alfanumerico, ogni cella è identificata da un numero intero positivo, chiamato "indice";
*invece del punto, per indicare una cella si usa una notazione diversa.
Riga 16:
 
Il tipo dell'array è sempre un tipo riferimento, e si indica apponendo una coppia di parentesi quadre al ''component type''. Esempi:
*<ttcode>int[]</ttcode> indica il tipo <ttcode>array di int</ttcode>
*<ttcode>Object[]</ttcode> indica il tipo <ttcode>array di Object</ttcode>
*<ttcode>int[][]</ttcode> indica il tipo array il cui ''component type'' è <ttcode>int[]</ttcode>,<ref>In altre parole: indica il tipo di un array le cui celle referenziano degli array di int.</ref> quindi, in definitiva, indica il tipo <ttcode>array di array di int</ttcode>
 
Si noti che il tipo di un array non include '''mai''' il numero delle celle. Per conoscere questo numero, si usa il campo campo <ttcode>length</ttcode>, il quale si comporta come un campo <ttcode>public final int</ttcode>.
 
; Celle
L'indice della prima cella è sempre <ttcode>0</ttcode><ref>In gergo, con terminologia inglese, si dice che gli indici sono ''0-based''. Esistono linguaggi che hanno array ''1-based'' o che permettono di scegliere indici arbitrari.</ref> e, pertanto, l'indice dell'ultima cella è sempre <ttcode>n - 1</ttcode>, dove <ttcode>n</ttcode> è il numero di celle totali.
 
Ad esempio:
:<ttcode>System.out.println(i[0]);</ttcode> stampa a video il valore della prima cella dell'array referenziato dalla variabile <ttcode>i</ttcode>.
:<ttcode>i[0] = 5;</ttcode> assegna il valore intero <ttcode>5</ttcode> alla prima cella dell'array.
 
Più precisamente, l'accesso a una cella, in lettura o in scrittura, si identifica 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 <ttcode>int</ttcode> tramite [[Java/Tipi di dato#Conversioni|cast implicito]].
 
; Clonazione
Riga 38:
 
; Inizializzando le celle con il valore di default
È possibile allocare un array in memoria servendosi della parola-chiave <ttcode>new</ttcode>:
:<ttcode>int[] i = new int[10];</ttcode>
Il numero di elementi tra parentesi quadre è obbligatorio.
 
Tutte le celle sono automaticamente [[Java/Oggetti#Inizializzazione dei campi|inizializzate]] con il valore di default del ''component type''. Nell'esempio appena mostrato, tutti gli ''slot'' dell'array referenziato dalla variabile <ttcode>i</ttcode> valgono inizialmente <ttcode>0</ttcode>.
 
Ad esempio, la scrittura <code>new byte[1024]</code> crea un array di 1024 celle, inizializzate al valore 0; <code>new Object[1024]</code> crea un array di 1024 celle, inizializzate con il valore ''null''.
Riga 64:
int[] numeri = { -1, 0, 0 };
</source>
dove <ttcode>new int[]</ttcode> viene inserito in automatico dal compilatore. Si tratta di un caso speciale, che funziona solo se l'array viene creato insieme alla dichiarazione della variabile, quindi il codice seguente non compila:
<source lang="Java">
int[] numeri;
Riga 70:
</source>
 
perché la dichiarazione e l'inizializzazione della variabile <ttcode>numeri</ttcode> ora sono due istruzioni diverse.
 
; Deallocazione
Riga 86:
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 <ttcode>Serializable</ttcode> e <ttcode>Cloneable</ttcode><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:
Riga 102:
 
=== Gerarchia delle classi ===
È sempre possibile convertire un array verso il tipo <ttcode>Object</ttcode> tramite cast implicito, in quanto tutti gli array sono oggetti.
 
In aggiunta, tutti gli array possono essere convertiti verso i tipi {{Java/Javadoc|java.lang.Cloneable|javadoc=java/lang/Cloneable.html}} e {{Java/Javadoc|java.io.Serializable|javadoc=java/io/Serializable.html}}.
In particolare,
*gli array supportano il metodo <ttcode>clone()</ttcode>;
*è possibile serializzare gli array come qualunque altro oggetto:
<source lang="Java">
Riga 114:
 
=== Gerarchia fra tipi array ===
Il tipo di un array creato con <ttcode>new T[...]</ttcode> è <ttcode>T[]</ttcode>. Se <ttcode>S</ttcode> è un supertipo di <ttcode>T</ttcode>, allora ogni array di tipo <ttcode>T[]</ttcode> può essere convertito verso il tipo <code>S[]</ttcode> tramite cast implicito; la conversione inversa richiede il cast esplicito.
 
Questo significa che tutti gli array di oggetti possono essere convertiti verso <code>Object[]</code>.
Riga 175:
... // istruzioni
</source>
Questo ciclo fa sì che le istruzioni che costituiscono il corpo del ''for'' siano eseguite una volta in più: nell'ultima iterazione, <ttcode>i</ttcode> è pari al valore di <ttcode>array.length</ttcode>, ovvero un indice fuori dai limiti dell'array (cioè <ttcode>0</ttcode> e <ttcode>array.length - 1</ttcode>). Un simile errore viene scoperto solo a ''run-time'', quando il programma [[#ArrayIndexOutOfBoundsException|genera una ArrayIndexOutOfBoundsException]] non prevista.
 
=== For each ===
Riga 225:
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/>
In certi casi, una collezione personalizzata permette di risparmiare memoria, in quanto non tutto il contenuto deve risiedere in memoria. Si pensi ad una lunga sequenza di elementi uguali tra loro: in alternativa, si può conservare una sola copia del valore, e simulare una collezione di grandi dimensioni manipolando gli indici.
<ref group="A">Vedi anche: [http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#nCopies(int,%20T) documentazione del metodo <ttcode>java.util.Collections.nCopies()</ttcode>]</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: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.
Riga 287:
L'allocazione statica e quella automatica richiedono che, a tempo di compilazione, sia nota la quantità massima di memoria che l'array occuperà a run-time. Il compilatore del C++ ha bisogno di conoscere non solo il tipo, ma anche il numero delle celle, che infatti va indicato obbligatoriamente nell'istruzione che ''dichiara'' l'array. Quest'ultimo può essere utilizzato subito dopo l'istruzione che lo dichiara, mentre in Java bisogna ''allocarlo'' esplicitamente.
 
Oltre agli array, anche i puntatori del C++ supportano l'operatore "parentesi quadre", e l'allocazione dinamica di un array tramite <ttcode>new</ttcode> restituisce appunto un puntatore. Tuttavia, esso andrà memorizzato in una variabile di tipo puntatore, e non in una variabile array, perché quest'ultima è un puntatore ''costante''. In effetti, in C++, la sintassi degli array "maschera" operazioni di accesso e manipolazione di puntatori (aritmetica, dereferenziazione).
 
Poiché il C++ non è dotato di garbage-collector, un array allocato dinamicamente va deallocato dopo essere stato utilizzato (l'istruzione che permette di fare questo è <ttcode>delete[]</ttcode>, ed eventualmente può essere necessario iterare lungo l'array per deallocarne a loro volta i singoli elementi). Il Java ha garbage-collector, quindi gli array non vanno deallocati esplicitamente.
 
Per massimizzare le prestazioni del codice eseguibile, in C++ è consentito leggere o scrivere in una cella il cui indice è fuori dai limiti dell'array. Di fatto, questa operazione consiste nell'accesso ad una locazione di memoria non occupata da quell'array, che pertanto potrebbe non essere allocata affatto, oppure allocata dal programma o dal sistema per altri usi (variabili, istruzioni del programma, ecc.). L'ambiente di esecuzione non è tenuto a segnalare questa situazione, che è evidentemente non voluta dal programmatore, e i cui risultati non possono essere previsti a priori. In Java, la VM lancia una eccezione se si tenta di accedere ad una cella che è fuori dai limiti dell'array.