1 / 131

Programmazione Parametrica ( a.k.a. Generics )

Programmazione Parametrica ( a.k.a. Generics ). Introduzione ai meccanismi e concetti della programmazione parametrica Generics e relationi di sottotipo wildcards generics e vincoli Implemendaizone di classi e metodi parametrici Supporto per i generics nella JVM.

kathrynt
Download Presentation

Programmazione Parametrica ( a.k.a. Generics )

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Programmazione Parametrica(a.k.a.Generics )

  2. Introduzione ai meccanismi e concetti della programmazione parametrica • Generics e relationi di sottotipo • wildcards • generics e vincoli • Implemendaizone di classi e metodi parametrici • Supporto per i generics nella JVM

  3. Programmazione polimorfa • Polimorfo ~ multiforme, di molti tipi • Programmazione polimorfa: creazione di costrutti (classi e metodi) che possono essere utilizzati in modo uniforme su dati di tipo diverso • In Java, tradizionalmente ottenuta mediante i meccanismi di sottotipo ed ereditarietà • Da Java 1.5. mediante i meccanismi di parametrizzazione di tipo (a.k.a. generics)

  4. Variabili di Tipo • Le variabili (o parametri) di tipo pemettono di creare astrazioni di tipo • Classico caso di utilzzo nelle classi “Container” • E = variabile di tipo • astrae (e rappresenta) il tipo delle componenti public class ArrayList<E> { public ArrayList() { . . . } public void add(E element) { . . . } . . .} Continua

  5. Variabili di Tipo • Possono essere istanziate con tipi classe o interfaccia • Vincolo: tipi che istanziano variabili di tipo non possono essere primitivi (devono essere tipi riferimento) • Classi wrapper utili allo scopo ArrayList<BankAccount>ArrayList<Measurable> ArrayList<double> // No! ArrayList<Double>

  6. Variabili di tipo e controlli di tipo • Utilizzare variabili di tipo nella programmazione permette maggiori controlli sulla correttezza dei tipi in fase di compilazione • Aumenta quindi la solidità e robustezza del codice Continua

  7. Variabili di tipo e controlli di tipo • Un classico caso di utilizzo di containers • Il cast è problematico, per vari motivi • verboso, fonte di errori a run time • Ma necessario per la compilazione e per localizzare l’eventuale errore a run time List intList = new LinkedList(); intList.add(new Integer(0)); Integer x = (Integer) intList.iterator().next(); Continua

  8. Variabili di tipo e controlli di tipo • Container generici: più sintetici ed eleganti • Compilatore può • stabilire un invariante sugli elementi della lista • garantire l’assenza di errori a run-time in forza di quell’invariante. List<Integer> intList = new LinkedList<Integer>(); intList.add(new Integer(0)); Integer x = intList.iterator().next(); Continua

  9. Variabili di tipo e controlli di tipo • Ora non è possibile aggiungere una stringa ad intlist:List<Integer> • Le variabili di tipo rendono il codice parametrico più robusto e semplice da leggere e manutenere List<Integer> intList = new LinkedList<Integer>(); intList.add(new Integer(0)); Integer x = intList.iterator().next();

  10. Classi parametriche: definizione • Un frammento delle interfacce List e Iterator nel package java.util.* // nulla di particolare, a parte i parametri // tra parentesi angolate public interface List<E> { void add(E x); Iterator<E> iterator(); } public interface Iterator<E> { E next(); boolean hasNext(); }

  11. Classi parametriche: uso • Quando utilizziamo un tipo parametrico, tutte le occorrenze dei parametri formali sono rimpiazzate dall’argomento (parametro attuale) • Meccanismo simile a quello del passaggio dei parametri in un metodo • Diversi usi generano tipi diversi • Ma . . . • classi parametriche compilate una sola volta • danno luogo ad un unico file.class

  12. Sintassi: uso GenericClassName<Type1, Type2, . . .> Esempio:   ArrayList<BankAccount> HashMap<String, Integer> Scopo: Fornire tipo specifici per ciascuna delle variabili di tipo introdotte nella dichiarazione

  13. Esempio: Pair<T,S> • Una semplice classe parametrica per rappresentare coppie di oggetti public class Pair<T, S>{ public Pair(T firstElement, S secondElement) { first = firstElement; second = secondElement; } public T getFirst() { return first; } public S getSecond() { return second; } private T first; private S second;} Continua

  14. Esempio: Pair<T,S> • Una semplice classe parametrica per rappresentare coppie di oggetti: • I metodi getFirst e getSecond restituiscono il primo e secondo elemento, con i tipi corrispondenti Pair<String, BankAccount> result = new Pair<String, BankAccount> ("Harry Hacker", harrysChecking); String name = result.getFirst();BankAccount account = result.getSecond();

  15. Variabili di tipo: convenzioni

  16. Esempio: LinkedList<E> public class LinkedList<E>{ . . . public E removeFirst() { if (first == null) throw new NoSuchElementException(); E element = first.data; first = first.next; return element; } . . . private Node first; private class Node { E data; Node next; }} Continua

  17. Esempio: LinkedList<E> private class Node<F>{ F data; Node next;}public class LinkedList<E>{ . . . public E removeFirst() { if (first == null) throw new NoSuchElementException(); E element = first.data; first = first.next; return element; } . . . private Node<E> first; } Continua

  18. Esempio: LinkedList<E> • Notiamo la struttura della classe ausiliaria che specifica la struttura dei nodi • Se la classe è interna, come in questo caso, non serve alcun accorgimento • all’interno di Node possiamo utilizzare il tipo E, il cui scope è tutta la classe • Se invece la classe è esterna, dobbiamo renderla generica public classListNode<E>

  19. File LinkedList.java 001: import java.util.NoSuchElementException; 002: 003: /** 004: A linked list is a sequence of nodes with efficient 005: element insertion and removal. This class 006: contains a subset of the methods of the standard 007: java.util.LinkedList class. 008: */ 009:public class LinkedList<E> 010: { 011: /** 012: Constructs an empty linked list. 013: */ 014:public LinkedList() 015: { 016: first = null; 017: } 018: Continua

  20. File LinkedList.java 019: /** 020: Returns the first element in the linked list. 021: @return the first element in the linked list 022: */ 023:public E getFirst() 024: { 025:if (first == null) 026:throw new NoSuchElementException(); 027:return first.data; 028: } 029: 030: /** 031: Removes the first element in the linked list. 032: @return the removed element 033: */ 034:public E removeFirst() 035: { Continua

  21. File LinkedList.java 036:if (first == null) 037:throw new NoSuchElementException(); 038: E element = first.data; 039: first = first.next; 040:return element; 041: } 042: 043: /** 044: Adds an element to the front of the linked list. 045: @param element the element to add 046: */ 047:public void addFirst(E element) 048: { 049: Node newNode = new Node(); 050: newNode.data = element; 051: newNode.next = first; 052: first = newNode; 053: } Continua

  22. File LinkedList.java 054: 055: /** 056: Returns an iterator for iterating through this list. 057: 058: */ 059:public ListIterator<E> listIterator() 060: { 061:return new LinkedListIterator(); 062: } 063: 064:private Node first; 065: 066:private class Node 067: { 068: E data; 069: Node next; 070: } 071: Continua

  23. LinkedListIterator • La definiamo come classe interna di LinkedList<E> • Implements l’interfaccia ListIterator<E> • Ha accesso al campo first e alla classe interna Node

  24. Classe LinkedListIterator 072:private class LinkedListIterator implements ListIterator<E> 073: { 074: /** 075: Costruisce un iteratore posizionato sul primo 076: elemento della lista 077: */ 078:public LinkedListIterator() 079: { 080: last = null; // ultimo nodo visitato 081: previous = null; // precedente a position 082: } 083: Continua

  25. LinkedListIterator – next() 084: /** 085: Posizione l’iteratore sul prossimo. 086: @return il prossimo elemento 087: */ 088: public E next() 089: { 090:if (!hasNext()) 091:throw new NoSuchElementException(); 092: previous = last; // Remember for remove 093: 094:if (last == null) 095: last = first; 096:else 097: last = last.next; 098: 099:return last.data; 100: } 101: 102: Continua

  26. LinkedListIterator–hasNext() 102: /** 103: Testa se c’è un elemento dopo l’ultimo 104: visitato. 105: @return true se esiste un elemento dopo 106: l’ultimo visitato 107: */ 108:public boolean hasNext() 109: { 110:if (last == null) 111:return first != null; 112:else 113:return last.next != null; 114: } 115: 116: Continua

  27. LinkedListIterator–add() 117: /** Aggiunge un elemento dopo last e sposta 118: l’iteratore sul prossimo elemento. 119: */ 121: public void add(E element) 122: { 123: if (last == null) 124: { 125:addFirst(element); last = first; 127: } 128:else 129: { 130: Node newNode = new Node(); 131: newNode.data = element; 132: newNode.next = last.next;//(1) 133: last.next = newNode; // (2) 134: last = newNode; // (3) 135: } 136: previous = last; // (4) 137: } Continua

  28. last LinkedListIterator–add()

  29. LinkedListIterator–remove() 140: /** Rimuove l’elemento puntato da last. Può essere 141: invocato solo dopo una chiamata a next() 142: */ 143:public void remove() 144: { 145:if (previous == last) 146:throw new IllegalStateException(); 147: 148:if (last == first) 149: { 150: removeFirst(); 151: } 152:else 153: { 154: previous.next = last.next; // (1) 155: } 156: last = previous; // (2) 157: } Continua

  30. last LinkedListIterator–remove()

  31. Classe LinkedListIterator 159: /** 160: Sets the last traversed element to a different 161: value. 162: @param element the element to set 163: */ 164:public void set(E element) 165: { 166:if (position == null) 167:throw new NoSuchElementException(); 168: position.data = element; 169: } 170: 171:private Node position; 172:private Node previous; 173: } // end LinkedListIterator 174: } // end LinkedList

  32. File ListIterator.java 01: /** 02: A list iterator allows access of a position in a linked 03: list. This interface contains a subset of the methods 04: of the standard java.util.ListIterator interface. The 05: methods for backward traversal are not included. 06: */ 07:public interface ListIterator<E> 08: { 09: /** 10: Moves the iterator past the next element. 11: @return the traversed element 12: */ 13: E next(); 14: 15: /** 16: Tests if there is an element after the iterator 17: position. Continua

  33. File ListIterator.java 18: @return true if there is an element after the iterator 19: position 20: */ 21:boolean hasNext(); 22: 23: /** 24: Adds an element before the iterator position 25: and moves the iterator past the inserted element. 26: @param element the element to add 27: */ 28:void add(E element); 29: 30: /** 31: Removes the last traversed element. This method may 32: only be called after a call to the next() method. 33: */ Continua

  34. File ListIterator.java 34:void remove(); 35: 36: /** 37: Sets the last traversed element to a different 38: value. 39: @param element the element to set 40: */ 41:void set(E element); 42: }

  35. Generics e sottotipi • Consideriamo • La prima istruzione è sicuramente legale, la seconda è più delicata … • Number è una classe astratta che ha Integer , Double e altre classi wrapper come sottotipi • Per capire se la seconda istruzione sia da accettare come legale continuiamo con l’esempio … List<Integer> li = new ArrayList<Integer>(); List<Number> ln = li; Continua

  36. Generics e sottotipi List<Integer> li = new ArrayList<Integer>(); List<Number> ln = li; ln.add(3.14); Integer i = li.get(0); // uh oh ... • Come si vede abbiamo un problema • nella terza istruzione inseriamo un Double (via auto-boxing, ricordate?) • nella quarta estraiamo un Integer ! • Il vero problema è nella seconda istruzione • soluzione: errore di compilazione per l’assegnamento al secondo Continua

  37. Generics e sottotipi • In generale, dati due tipi A e B , ed tipo generico C<T> abbiamo che: • Quindi, per le stesse ragioni di prima A ≤ B non implica C<A> ≤ C<B> Set<Integer> non è sottotipo di Set<Object> Continua

  38. Generics e sottotipi • Le limitazione sulle relazioni di sottotipo sono contro-intuitive • uno degli aspetti più complessi dei generics • Non solo … sono anche decisamente troppo restrittive • illustriamo con un esempio Continua

  39. Generics e sottotipi • Un metodo che stampa gli elementi di una collezione • Versione tradizionale void printCollection(Collection c) { Iterator i = c.iterator(); for (k = 0; k < c.size(); k++) { System.out.println(i.next()); } } Continua

  40. Generics e sottotipi • Stampa degli elementi di una collezione • Versione generics: primo tentativo • utile solo per Collection<Object> non per qualsiasi collezione • Collection<Object> non è il supertipo di tutte le collezioni void printCollection(Collection<Object> c) { for (Object e:c) System.out.println(e); } Continua

  41. Wildcards • Stampa degli elementi di una collezione • Versione generics: secondo tentativo • Collection<?>è il supertipo di tutte leCollections • la wildcard ?indica un qualche tipo, non specificato void printCollection(Collection<?> c) { for (Object e:c) System.out.println(e); } Continua

  42. Wildcards • Possiamo estrarre gli elementi di c al tipo Object • Corretto perché, qualunque sia il loro vero tipo, sicuramente è sottotipo di Object void printCollection(Collection<?> c) { for (Object e:c) System.out.println(e); } Continua

  43. Wildcards • D’altra parte … • visto che non sappiamo esattamente quale tipo indica ?, non possiamo assegnare valori Collection<?> c = new ArrayList<String>(); c.add(new String()); // errore di compilazione! Continua

  44. Domanda • Date un esempio di codice che causerebbe errore in esecuzione se permettessimo di aggiungere elementi a Collection<?>

  45. Risposta • L’ultima istruzione invocherebbe intValue() sul primo elemento di ci • ma quell’elemento ha tipo String … • In realtà il compilatore anticipa l’errore, segnalando il problema sulla add() Collection<Integer> ci = new ArrayList<Integer>; Colletion<?> c = ci; c.add(“a string”); ci.get(0).intValue();

  46. Wilcards con vincoli (bounded) • Shapes: un esempio classico public abstract class Shape { public abstract void draw(Graphics g); } public class Circle extends Shape { private int x, y, radius; public void draw(Graphics g) { ... } } public class Rectangle extends Shape { private int x, y, width, height; public void draw(Graphics g) { ... } } Continua

  47. Wilcards con vincoli (bounded) • Graphics e il metodo draw() • Solito problema:drawAll() non può essere invocato su unaList<Circle> public class Graphics { // disegna una shape public void draw(Shape s) { s.draw(this); } // disegna tutte le shapes di una lista public void drawAll(List<Shape> shapes) { for (Shape s:shapes) s.draw(this) } . . . } Continua

  48. Bounded Wilcards • Quello che ci serve è un metodo che accetti liste di qualunque (sotto) tipo di Shape • List<? extends Shape> • bounded wildcard • indica un tipo sconosciuto, sottotipo diShape • il bound può essere qualunque tipo riferimento (classe o interfaccia) • Ora il metodo ha la flessibilità necessaria e desiderata void drawAll(List<? extends Shape> shapes) { ... } Continua

  49. Bounded Wilcards • Graphics e il metodo draw() public class Graphics { // disegna una shape public void draw(Shape s) { s.draw(this); } // disegna tutte le shapes di una lista public void drawAll(List<? extends Shape> shapes) { for (Shape s:shapes) s.draw(this) } . . . } Continua

  50. Bounded Wilcards • D’altra parte, c’è sempre un prezzo da pagare • Il solito vincolo … • Non possiamo modificare strutture con questi tipi [ perché? ] void addRectangle(List<? extends Shape> shapes) { // errore di compilazione shapes.add(new Rectangle()); }

More Related