"Andrea Francia"
Post by Andrea FranciaNon ho capito bene questa parte.
Comunque tutto molto interessante.
Penso che riassumendo dica semplicemente che ... se per compatibilita' si
intende che vecchio codice (senza generics) puo' girare su nuova JVM (con
generics) e che il nuovo codice (con generics) su nuova VM possa anche
chiamare vecchio codice senza generics, allora la type erasure non era
necessaria.
In Sun avevano pero' un requisito aggiuntivo (non utilissimo) che rendeva la
type erasure necessaria:
Il requisito diceva che la classe con generics e quella senza dovevano
essere la stessa classe cosi' che una istanza di tale classe potesse essere
usata nel nuovo codice con generics e nel vecchio senza, insomma la stessa
istanza usata in due modi diversi.
Ok, i primi requisiti sono importanti in quanto il codice puo' avere una
vita di parecchi anni, e quindi e' importrante che vecchio codice possa
girare su nuova VM. E' importantissimo anche che il nuovo codice possa
chiamare del vecchio codice che non usa generics. Non e' pero'
indispensabile avere la possibilita' di passare una generic collection a del
vecchio codice scritto senza generics. Se usiamo una library vecchia,
potremo semplicemente assicurarci di passare un qualche cosa che la libreria
e' in grado di usare. Quindi se la libreria vuole un List, noi potremmo
semplicemente passare List o ArrayList, ma non un List<Integer> o un
ArrayList<Integer>... ma no, questo non bastava a Sun.
Questo requisito parzialmente utile temporaneamente, durante il periodo di
transazione ha reso i generics meno utili di quanto sarebbero potuti essere.
Se guardi ArrayList.java dice:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
a dimostrazione che ArrayList e ArrayList<E> sono la stessa cosa, la stessa
classe.
Quindi e' ovvio che poi ArrayList.java segue con un bel:
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
private transient Object[] elementData;
ovvero un Object[] e non un E[], ed e' intuibile che debba usare type
erasure.
Quindi torniamo a quando dicevo che :
new ArrayList<Integer>();
new ArrayList<String>();
new ArrayList();
in realta' non sono tre tipi diversi ma lo stesso tipo (una sorta di
ArrayList<Object>).
Post by Andrea FranciaPost by Andrea FranciaSono due tipi diversi.
Tant'e vero che sia
oggetti = stringhe; // non compila
stringhe = oggetti; // non compila
il fatto che non compili e' semplicemente un controllino che fa il
compilatore per essere carino. Poi sei libero di chiamarli due tipi diversi,
dipende da cosa si intende per tipo, suppongo nessuna definizione sia errata
e nessuna giusta, ma se uno ha usato i templates in C++ fa davvero fatica a
dire che sono due tipi diversi. (in C++ il template viene di fatto usato
come stampino per produrrebbe due classi diverse che venono compilate in
tempi diversi ed hanno nomi diversi e posti diversi nel binary e non hanno
type erasure etc..., non e' l'implementazione piu' elegante, ma sicuramente
questa definisce due tipi diversi!).
Quindi type erasure e' stata fatta per permettere questo uso misto di una
istanza:
// Nuovo codice:
final List<String> names = new ArrayList<String>();
names.add("Tommy");
// ...
// Vecchio codice:
final List str1 = names;
Qui, sarebbe bastato passare un List invece che un List<String> al vecchio
codice, se fossero stati due tipi diversi (due interface diverse).
// Vecchio codice:
final List names = new ArrayList();
names.add("Tommy");
// ...
// Nuovo codice:
final List<String> str1 = names;
Qui, il vecchio codice crea una Lista che contiene solo stringhe, ma che
potrebbe contenere qualsiasi cosa. Nel tuo nuovo codice che chiama questo
vecchio codice pero' non vuoi dover usare List e fare i cast tutte le volte
cosi', cosi' hanno fatto in modo che List e List<String> siano la stessa
cosa e che tu possa usare tranquillamente i generics anche con oggetti che
sono stati creati senza generics (nel vecchio codice).
Questo richiede che i due siano in realta' lo stesso tipo... sarebbe stato
meglio se List e List<String> fossero state due interface diverse, ok,
dovevi continuare ad usare la vecchia senza generics nel nuovo codice o
perdere tempo a passare i dati da List a List<String> a seconda di quanto
siano importanti le prestazioni in quel punto.
Man mano che le librerie vengono scritte usando generics questo requisito
non necessario ma solo "nice to have" e' sempre meno utile, pero' ha
limitato severamente i generics in Java.
Magari la versione 7 risolve il problema ma per farlo ora dovrebbe comunque
creare qualche problema, quindi potevano farlo fin da subito.
che siano troppo comodi concordo in pieno, ma sarebbero potuti essere molto
piu' comodi.
Poi l'articolo parlava di boxing... ovvero il fatto che ArrayList tiene
Object in realta' rende impossibile fare ArrayList<int> in quanto int
essendo un primitivo non deriva da Object e quindi non si puo'. Questo rende
necessario quindi fare ArrayList<Integer> che probabilmente comporta tutta
una serie di conversioni da int a Integer e poi da Integer a int.. tutto non
necessario nella maggior parte dei casi.
Poi non fraintendere, uso i generics tutti i giorni e li trovo utile come li
trovi utili tu, ma penso solo potrebbero essere molto meglio.
Tommy