Java/Tipi di dato: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Riga 40:
 
== Conversioni ==
Le conversioni in Java si chiamano anche operazioni di ''cast''. Una conversione ammessa dal linguaggio può essere realizzata in due soli modi: con ''cast esplicito'' o con ''cast implicito''. Il primo si ha utilizzando l'apposito operatore; il secondo, invece, viene gestito in automatico dal compilatore e non ha ununa costruttosintassi specificospecifica. Ogni cast implicito può essere reso esplicito, se si vuole (a volte è utile per chiarezza).
 
L'idea che sta alla base di questoquesta meccanismo, in Java,differenza è che, in presenza di un'operazioneuna conversione che potrebbe avere risultati non previstiindesiderati, il programmatore deve "dichiarareconfermare" esplicitamente al compilatore di esserne consapevole e di volerla ugualmente effettuare<ref>L'esempio classico è la conversione di un numero con virgola (''float'' verso il tipoo ''intdouble'',) cheverso puòun portaretipo alintero, perché una troncamentoparte del numero nelva casopersa ci siano dei(i decimali). Questa operazione, infatti, costituisce, di fatto, una perdita di informazioni per il programma, e ilIl programmatore potrebbe non esserne consapevole al momento della scrittura del codice.</ref>. Questa "dichiarazioneconferma" vieneè effettuatascritta scrivendo esplicitamente lnell'operatore di cast peresplicito. Se le specifiche di linguaggio riconoscono che la conversione non può avere ''in nessun caso'' effetti indesiderati, allora è ammesso anche il cast implicito.
 
Per quanto riguarda i tipi base:
*non sono ammesse conversioni tra ''boolean'' e i tipi numerici; si noti che questo comportamento è differente da quello che si ha nel C;
*al contrario, sono ammesse tutte le conversioni da un certo tipo numerico verso un altro tipo numerico;
*ma richiedono necessariamente il cast esplicito tutte le conversioni da un tipo numerico più "grandecapiente" adverso uno più "piccolo" (per es. da ''long'' verso ''int'') o da un tipo con virgola verso un tipo intero.
 
Per quanto riguarda le classi:
Riga 54:
Il motivo è che
*nel primo caso, la conversione riesce sempre; per esempio, ogni istanza di [http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html java.util.ArrayList] sicuramente è anche un'istanza di [http://download.oracle.com/javase/6/docs/api/java/util/Collection.html java.util.Collection];
*nel secondo, invece, potrebbe non riuscire: un oggetto [http://download.oracle.com/javase/6/docs/api/java/util/Collection.html Collection] potrebbe non essere un'istanza di [http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html ArrayList], oppurema di [http://download.oracle.com/javase/6/docs/api/java/util/LinkedList.html LinkedList], oppure di [http://download.oracle.com/javase/6/docs/api/java/util/HashSet.html HashSet], o di qualche altro tipo ancora. In tal caso, a tempo di esecuzione, l'operatore di cast esplicito [[Java/Gestione delle eccezioni|lancerà una eccezione]] (di tipo [http://download.oracle.com/javase/6/docs/api/java/lang/ClassCastException.html ClassCastException]).
 
Le specifiche di linguaggio affermano che, se si cerca di convertire un oggetto di un tipo X ad un altro tipo Y di cui l'oggetto '''non''' è istanza, allora a tempo di esecuzione viene lanciata una eccezione (di tipo [http://download.oracle.com/javase/6/docs/api/java/lang/ClassCastException.html ClassCastException]). Dalle regole elencate sopra risulta evidente che una eccezione può essere lanciata solo dalle righe di codice che fanno uso di cast esplicito per la conversione.
 
=== Classi wrapper ===
{{Riquadro attenzione|titolo=Classi wrapper e collezioni|testo=
Il caso più comune è quello in cui si vuole aggiungere un intero ad una [http://download.oracle.com/javase/6/docs/api/java/util/List.html java.util.List]: si deve prima racchiudere il valore intero in un oggetto java.lang.Integer, dopodiché si aggiunge questo oggetto alla List.
}}
Dovunque sia necessario un oggetto in luogo di un valore di un tipo base, si può usare una delle classi wrapper definite nel package java.lang:
*boolean: [http://download.oracle.com/javase/6/docs/api/java/lang/Boolean.html java.lang.Boolean]
Line 74 ⟶ 69:
Esiste una classe anche per il tipo ''void'' [http://download.oracle.com/javase/6/docs/api/java/lang/Void.html java.lang.Void], sebbene questo tipo non definisca alcun valore. Essa è utilizzata in contesti particolari, tipicamente quando si usa la ''reflection''.
 
Per i tipi numerici esistono anche le classi [http://download.oracle.com/javase/6/docs/api/java/math/BigInteger.html java.math.BigInteger] e [http://download.oracle.com/javase/6/docs/api/java/math/BigDecimal.html java.math.BigDecimal], le quali, però, non sono considerate classi wrapper. Queste due classi permettono di rappresentare numeri interi o decimali arbitrariamente grandiarbitrari, uscendo fuorifuoriuscendo dai limiti imposti sulle dimensioniper deii tipi primitivi.
 
Le classi wrapper sono molto utili dovunque sia necessario interagire con una parte del programma scritta per lavorare su oggetti. Ad esempio, non è possibile aggiungere un intero ad una collezione, perché le collezioni sono scritte come contenitori di ''oggetti'', quindi è necessario prima racchiudere il numero in un oggetto, dopodiché si aggiunge questo oggetto alla collezione.
==== Autoboxing e unboxing ====
La famiglia dei tipi base e la famiglia dei tipi riferimento sono separate l'una dall'altra: esse definiscono due gerarchie distinte che non hanno alcun punto di giunzione. Per questo motivo, fino alla terza edizione delle specifiche di linguaggio, non erano ammesse conversioni tra tipi primitivi e tipi riferimento, né tramite ''cast'' esplicito, né tramite ''cast'' implicito.
 
==== Autoboxing e unboxing ====
Tuttavia, le classi wrapper definite nel package <tt>java.lang</tt> permettono di associare un oggetto a un valore del tipo primitivo corrispondente, e viceversa. Ad esempio, era possibile ottenere un oggetto <tt>Integer</tt> partendo da un <tt>int</tt>, invocando il costruttore [http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Integer.html#Integer(int) Integer(int)], ed è possibile ottenere il numero intero corrispondente tramite il metodo [http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Integer.html#intValue() intValue()]. Un discorso analogo vale per ciascuno degli altri tipi primitivi.
La famiglia dei tipi base e la famiglia dei tipi riferimento sono separate l'una dall'altra: essee definiscono due gerarchie distinte che non hanno alcun punto di giunzione. Per questo motivo, fino alla terza edizione delle specifiche di linguaggio, non erano ammesse conversioni tra tipi primitivi e tipi riferimento, né tramite ''cast'' esplicitoimplicito, né tramite ''cast'' implicitoesplicito.
 
Tuttavia,Ogni le classiclasse wrapper definite nel package <tt>java.lang</tt> permettonopermette di associare un oggetto a un valore del tipo primitivo corrispondente, e viceversa. Ad esempio, eraè possibile ottenere un oggetto <tt>Integer</tt> partendo da un numero di tipo <tt>int</tt>, invocando il costruttore [http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Integer.html#Integer(int) Integer(int)costruttore appropriato],; ed è possibile ottenereriottenere il numero intero corrispondenteinvocando tramitesull'oggetto il metodo [http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Integer.html#intValue() intValue()]. Un discorso analogo vale per ciascuno degli altri tipi primitivi.
Queste due operazioni (costruttore e metodo <tt>xxxValue()</tt>) sono di uso frequente dovunque sia necessario un oggetto in luogo di un valore di tipo primitivo; ad esempio, nelle collezioni.
 
Prima di Java 5, era necessario invocare esplicitamente i costruttori e i metodi <tt>xxxValue()</tt> appropriati. Per rendere più semplicesintetico e leggibile il codice che richiama queste operazioni, dalla terza versione delle specifiche di linguaggio (Java 5) in poi, è ammesso il ''cast implicito'' di un valore di un tipo primitivo verso il corrispondente tipo wrapper, e viceversa. Il compilatore inseriscelo sostituisce automaticamente l'invocazionecon aiuna istruzione che invoca i metodi o i costruttori suldel tipo wrapper utilizzato.
 
Quindi, da Java 5 in poi, è possibile scrivere una istruzione come:
<tt>Integer k = 3200;</tt>
<tt>Integerint kj = new Integer(3)k;</tt>
invece di:
<tt>Integer k = new Integer(200);</tt> // oppure Integer k = Integer.valueOf(3200);</tt><ref>Il metodo [http://download.oracle.com/javase/6/docs/api/java/lang/Integer.html#valueOf(int) valueOf(int)] è stato introdotto in Java 5.</ref>
<tt>Integer k = new Integer(3);</tt>
<tt>int j = k.intValue();</tt>
oppure di:
in quanto la conversioneprima forma viene tradotta automaticamente dal compilatore.
<tt>Integer k = Integer.valueOf(3);</tt><ref>Il metodo [http://download.oracle.com/javase/6/docs/api/java/lang/Integer.html#valueOf(int) valueOf(int)] è stato introdotto in Java 5.</ref>
in quanto la conversione viene tradotta automaticamente dal compilatore.
 
La conversione da tipo primitivo a tipo wrapper è detta ''autoboxing'',<ref group="F">[http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.7 The Java Language Specification, Chapter 5]</ref><ref group="F">[http://download.oracle.com/javase/1.5.0/docs/guide/language/autoboxing.html Java Programming Language, Autoboxing]</ref> mentre la conversione inversa è detta ''unboxing''<ref group="F">[http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.8 The Java Language Specification, Chapter 5]</ref>. Si noti che questi due meccanismi sono solo zucchero sintattico tradottoche dalmaschera compilatoredelle in una forma equivalente, ma più lunga da scrivere, perché coinvolge l'invocazioneinvocazioni a metodi o costruttori della classe del tipo wrapper in usometodo; quindi, in definitiva, non cambiano il fatto che i tipi primitivi siano '''distinti e separati''' dai tipi riferimento.
 
== Le stringhe ==