…………………………………………………………………….. Il linguaggio Java: aggiunte in Java 1.5 Una breve presentazione F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) GENERICI Java 1.5 introduce i generici: classi che hanno un parametro di tipo. Nelle versioni precedenti a Java 1.5 si può definire: List miaLista = new LinkedList(); miaLista.add(new(Integer(0)); Integer x = (Integer)miaLista.iterator().next(); Gli oggetti List possono contenere oggetti di qualunque tipo, e quindi quando si estrae un oggetto dalla lista è necessario fare il cast. F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) Nella nuova versione: List<Integer> miaLista = new LinkedList<Integer>(); miaLista.add(new(Integer(0)); Integer x = miaLista.iterator().next(); La miaLista può contenere solo oggetti Integer. Non è più necessario il cast nell'ultima istruzione: il compilatore sa che l'oggetto estratto è un Integer. F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) L'interface List è specificata nel package java.util come: public interface List<E> { void add(E x); .... } Quando si dichiara una variabile di tipo List<Integer>, il parametro formale E viene legato ad Integer. E' come se si usasse una nuova interface: public interface ListofInteger { void add(Integer x); .... F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) } Esempio In realtà la dichiarazione di un generico come List<Integer> non viene espansa come detto prima, cioè non vengono create copie multiple del codice di List, una per ogni valore del parametro. La dichiarazione di List<E> viene compilata una volta per tutte e genera un solo file class, come qualunque altra dichiarazione di classe o interfaccia. F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) Esempio public class Pila<T> { private LinkedList<T> list = new LinkedList<T>(); public boolean isEmpty() {return list.isEmpty();} public void push(T v) { list.addFirst(v);} public T pop() {return list.removeFirst();} public static void main(String[] args) { Pila<String> stack = new Pila<String>(); stack.push("a"); stack.push("bcd"); String s1 = stack.pop(); String s2 = stack.pop(); System.out.println(s1); System.out.println(s2); } } F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) GENERICI E SOTTOTIPI Con gli array è possibile scrivere: String[] as = new String[5]; Object[] ao = as; ao[0] = new Object(); il compilatore accetta questo programma, ma l'inteprete dà errore a runtime perché non si può assegnare un Object a un array di stringhe. Viceversa in List<String> ls = new ArrayList<String>(); List<Object> lo = ls; lo.add(new Object()); la seconda istruzione non è accettata dal compilatore, perché l'interprete non sarebbe in grado di scoprire l'errore a runtime nella istruzione successiva. F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) Il comportamento descritto prima è molto restrittivo. Ad esempio, il seguente metodo per stampare gli elementi di una collezione: void printCollection(Collection<Object> c) Iterator<Object> i = c.iterator(); for(k=0; k<c.size(); k++) System.out.println(i.next()); } { può essere usato solo per stampare gli elementi di una Collection<Object>, ma non può avere come parametro, ad esempio, una Collection<Integer>. F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) Per definire una collection di qualunque cosa si può usare la notazione Collection<?>. void printCollection(Collection<?> c) Iterator<?> i = c.iterator(); for(k=0; k<c.size(); k++) System.out.println(i.next()); } { Tuttavia, in Collection<?> c = new ArrayList<String>(); c.add(new Object()); il compilatore accetta la prima istruzione, ma non la seconda, perché non può garantire la correttezza del tipo dell'elemento che viene inserito nella collezione. F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) FOR EACH L'iterazione sulle collezioni mediante un Iterator è abbastanza noiosa da scrivere. JDK 1.5 introduce al suo posto una nuova istruzione for. Invece di: void printCollection(Collection<Object> c) Iterator<Object> i = c.iterator(); for(int k=0; k<c.size(); k++) System.out.println(i.next()); } { si può scrivere: void printCollection(Collection<Object> c) for(Object e : c) System.out.println(e); } { F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) LIMITAZIONI SUL “?” Consideriamo la classe astratta: public abstract class Forma { public abstract void disegna(); } e diverse sue sottoclassi come Cerchio, Rettangolo, ... che implementano il metodo disegna. Un metodo per disegnare le forme contenute in una lista potrebbe essere: public void disegnaTutto(List<Forma> forme) { for (Forma f: forme) f.disegna(); } F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) La definizione public void disegnaTutto(List<Forma> forme) { è restrittiva, perché il metodo disegnaTutto può essere applicato solo a una List<Forma> e non, per esempio, a una List<Rettangolo>. D'altra parte public void disegnaTutto(List<?> forme) { sarebbe troppo generale perché il ? può essere legato a qualunque tipo, in particolare ad Object che non ha il metodo disegna. F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) Il “?” può essere limitato con la notazione public void disegnaTutto(List<? extends Forma> forme) {// Body del metodo disegnaTutto } in cui il tipo degli elementi della lista può essere una qualunque sottoclasse di Forma, e quindi certamente avrà il metodo disegna. F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) AUTO-BOXING Le strutture come Collection possono contenere solo oggetti. Quindi per inserire un tipo primitivo (es. int) occorre convertirlo (boxing) nel corrispondente oggetto (es. Integer). Viceversa, quando si estrae un oggetto dalla collezione occorre riconvertirlo nel tipo primitivo (unboxing). Nella versione 1.5 boxing e unboxing sono fatti automaticamente dal compilatore. ArrayList<Integer> al = new ArrayList<Integer>(); PRIMA DI Java 1.5 IN Java 1.5 al.add(0, new Integer(25)); int x = (al.get(0)).intValue(); al.add(0, 25); int x = al.get(0); F. Damiani - Alg. & Lab. 04/05 (da A. Martelli - P.in Rete & L. 04/05) ESERCIZI (FACOLTATIVI) Riscrivere, usando i nuovi costrutti presenti in Java 1.5, il codice relativo ai seguenti esercizi svolti in laboratorio: •E6 •E7 •E8 •E9 •E12 F. Damiani - Alg. & Lab. 04/05