Programmazione Parametrica ( a.k.a. Generics )

Documenti analoghi
Programmazione Parametrica ( a.k.a. Generics )

Programmazione. ( a.k.a. Generics )

Programmazione Parametrica ( a.k.a. Generics )

Programmazione ad oggetti

Polimorfismo per Genericità in Java

Astrazioni Polimorfe e Tipi Generici

Cosa sono i Generics?

Generics in Java. Linguaggi Corso M-Z - Laurea in Ingegneria Informatica A.A

Cosa sono i Generics?

Capitolo 16. Programmazione generica. Cay S. Horstmann Concetti di informatica e fondamenti di Java quarta edizione

Il linguaggio Java: aggiunte in Java 1.5

Java (J2SE) 1.5 (5.0)

Cenni su programmazione con tipi generici (generics)

Subtype Polymorphism. Conversioni di tipo. Conversioni di tipo. Subtyping. Conversioni di tipo. Interfacce e subtype polimorfismo

Java generics PR

Polimorfismo parametrico vs polimorfismo per inclusione

Arrays Array L ay ist

Programmazione a Oggetti. Polimorfismo e Tipi Generici

Collezioni, mappe e iteratori (a cura del Prof. Marco Patella)

Programmazione generica

Conoscere l uso delle collezioni in Java. Conoscere il concetto di Generics (programmazione

Collezioni. (a cura del Prof. Marco Patella)

Java Generics. Sunto di quanto letto nel libro Java Generics and Collections di Maurice Naftalin & Philip Wadler O'REILLY

Generics. L9 Linguaggi Progr.II Unina 2

Generics & Collections

Generic. Contenitori generici per oggetti realizzati tramite il concetto di tipo parametrico. IL NUOVO APPROCCIO (java 1.5)

Java generics PR

JAVA GENERICS. Angelo Di Iorio Università di Bologna

Programmazione orientata agli oggetti Classi astratte e interfacce. Classi astratte - Interfacce

Programmazione orientata agli oggetti Classi astratte e interfacce. Classi astratte - Interfacce

Programmazione ad oggetti

Corso di Linguaggi di Programmazione

Corso di Algoritmi e Strutture dati Programmazione Object- Oriented in Java (Parte I)

Introduzione Generics Iteratori. Collezioni in Java. Dr. Giulio Pellitta. 13 aprile 2011

Esercizio: Lista Circolare

STRUTTURE DATI: OLTRE GLI ARRAY LISTE

Esempio su strutture dati dinamiche: ArrayList

Corso di Algoritmi e Strutture Dati con Laboratorio. Java Collections Framework (I parte)

Programmazione orientata agli oggetti Classi astratte e interfacce

Esempio su strutture dati dinamiche: ArrayList

Interfacce. Dichiarazioni di tipi riferimento che descrivono oggetti in modo astratto Specificano solo le firme dei metodi.

Programmazione. Cognome... Nome... Matricola... Prova scritta del 11 luglio 2014

Richiami Java e Arrays

Programmazione. Cognome... Nome... Matricola... Prova scritta del 22 settembre Negli esercizi proposti si utilizzano le seguenti classi:

STRUTTURE DINAMICHE. (slide: A. Baratè L.A. Ludovico) Programmazione per la Musica Adriano Baratè

Testo di Riferimento (usato nei corsi precedenti)

OCA JAVA 8 SE PROGRAMMER I DOCENTE: DOTT. FAUSTO DELL ANNO

JAVA GENERICS. Java Interface e astrazione. CSE 331 Au

JAVA GENERICS. Verso i (pi generici in Java: un esempio

INFORMATICA III Parte B -Progettazione e Algoritmi

Gerarchie e polimorfismo: liste

Introduzione a Java. Giovanni Pardini. Dipartimento di Informatica Università di Pisa. 4 Java. Sommario. Iteratori.

Linguaggi di programmazione II AA 2010/2011 Esercitazione 2

PROGRAMMAZIONE Java Generics

Corso di Linguaggi di Programmazione

PROGRAMMAZIONE 2 4. Java: un modello operazionale

Corso di Linguaggi di Programmazione

Le gerarchie di tipi: implementazioni multiple e principio di sostituzione

Metodologie di Programmazione. ovvero, Principi e Tecniche per la costruzione di programmi

Riuso di classi. Ereditarietà. Ereditarietà. Spesso si ha bisogno di classi simili

Capitolo 14 Introduzione alle strutture di dati. Cay S. Horstmann Concetti di informatica e fondamenti di Java quarta edizione

Capitolo 17. Introduzione alle strutture di dati. Capitolo 17 Introduzione alle strutture di dati

Programmazione a Oggetti Lezione 7. Il linguaggio Java: aspetti generali

Esempi al calcolatore su: 1) Costruttori ed ereditarietà 2) Subtyping e Polimorfismo

Esempio 2: Subtyping

Programmazione a Oggetti Lezione 11. Eccezioni e Packages

Strutture dati. Il che cosa e il come. F. Damiani - Alg. & Lab. 04/05

Generics. L8 Linguaggi prog. II Unina 2

Fondamenti di Informatica

Introduzione al Java Collections Framework. Progettazione del Software Anno Accademico Interfacce del Collections Framework

Agent and Object Technology Lab Dipartimento di Ingegneria dell Informazione Università degli Studi di Parma. Ingegneria del software A

Progettazione del Software Anno Accademico

Metodi di una Collection

Parte I Java. Metodologie di Programmaziona Secondo Appello, 14/2/2006 1

E21 Esercizi sulle collezioni in Java

Array 1. Array: sequenza di valori omogenei (cioè dello stesso tipo). Costruire un array: new double[10]

Notazione grafica UML

I L IN I GU G AGG G I G O

Fondamenti di informatica T-1 (A K) Esercitazione 2 Basi del linguaggio Java

Capitolo 6. Uso della gerarchia. c 2005 Pearson Education Italia Capitolo 6-1 / 125

ArrayList. Prof. Francesco Accarino IIS Altiero Spinelli Via Leopardi132 Sesto San Giovanni

Introduzione ai tipi parametrici (Generics) in Java. Algoritmi e Laboratorio a.a Lezioni. Nota linguistica

Ereditarietà (ultima)

Ereditarietà (ultima)

TIPI PRIMITIVI E CLASSI WRAPPER

Corso di Fondamenti di Informatica I

Liste doppie. Doubly Linked Lists. GT: 6.2 (e 3.3) Argomenti della lezione

Implementare un'interfaccia

Scope e visibilità per classi

3. Il sistema dei tipi I tipi wrapper

Introduzione al Java Collections Framework. Java Collections Framework (cont.) Interfacce del Collections Framework

Esempio su strutture dati dinamiche: ArrayList

PROGRAMMAZIONE 2 Gerarchie di 9pi: implementazioni mul9ple e principio di sos9tuzione

3. Il sistema dei tipi I tipi wrapper

Introduzione al Java Collections Framework

Ingegneria del Software 1: Generici e Collezioni

Transcript:

Programmazione Parametrica ( a.k.a. Generics )

Programmazione parametrica: introduzione Generics e relationi di sottotipo wildcards generics e vincoli Implementazione di classi e metodi parametrici Supporto per i generics nella JVM Collections

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. anche mediante i meccanismi di parametrizzazione di tipo (a.k.a. generics)

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

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

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

Variabili di tipo e controlli di tipo Un classico caso di utilizzo di containers List intlist = new LinkedList(); intlist.add(new Integer(57)); Integer x = (Integer) intlist.get(0); 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 Continua

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

Variabili di tipo e controlli di tipo List<Integer> intlist = new LinkedList<Integer>(); intlist.add(new Integer(0)); Integer x = intlist.get(0); 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

Classi parametriche: uso Usare un tipo parametrico = istanziarlo per creare riferimenti e oggetti List<Integer> intlist = new LinkedList<Integer>(); tutte le occorrenze dei parametri formali sono rimpiazzate dall argomento (parametro attuale) Diversi usi generano tipi diversi Ma... classi parametriche compilate una sola volta danno luogo ad un unico file.class

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

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

Variabili di tipo: convenzioni Variabile E K V T,S,U Significato Inteso Tipo degli elementi in una collezione Tipo delle chiavi in una mappa Tipo dei valori in una mappa Tipi generici

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

Esempio: LinkedList<E> Notiamo la struttura della classe Node se la classe è interna, come nell esempio, 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

Esempio: LinkedList<E> 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

Generics e sottotipi I meccanismi di subtyping si estendono alle classi generiche class C<T> implements / extends D<T>... C<T> <: D<T> per qualunque T Analogamente: class C<T> implements / estends D... C<T> <: D per qualunque T Sembra tutto facile, MA...

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

Generics e sottotipi List<Integer> li = new ArrayList<Integer>(); List<Object> lo = li; // type error lo.add( uh oh )); Integer i = li.get(0); // uh oh... Problema nella terza istruzione inseriamo un Double nella quarta estraiamo un Integer! Errore è nella seconda istruzione soluzione: errore di compilazione per l assegnamento Continua

Generics e sottotipi In generale: A B NON implica C<A> C<B> Quindi, ad esempio: Set<Integer> NON è sottotipo di Set<Object> Come dimostrato, vincoli necessari per la correttezza del principio di sostituibilità

Generics e sottotipi Limitazione sul subtyping con generics contro-intuitive uno degli aspetti più complessi dei generics Spesso anche troppo restrittive illustriamo con un esempio Continua

Generics e sottotipi Stampa gli elementi di una qualunque collection Primo tentativo static void printcollection(collection<object> els) for (Object e:els) System.out.println(e); els.add( pippo ); // ok Inutile: Collection<Object> non è il supertipo di Collection<T> per alcun T!= Object Continua

Wildcards Stampa degli elementi di una collezione Secondo tentativo static void printcollection(collection<?> els) for (Object e:els) System.out.println(e); els.add( pippo ); // ko Collection<?> è supertipo di qualunque Collection<T> Wildcard? indica un qualche tipo, non specificato Continua

Wildcards void printcollection(collection<?> els) for (Object e:els) System.out.println(e); Possiamo estrarre gli elementi di els al tipo Object Corretto perché, qualunque sia il loro vero tipo, sicuramente è sottotipo di Object Continua

Wildcards Però Collection<?> c = new ArrayList<String>(); c.add(new String()); // errore di compilazione! Poichè non sappiamo esattamente quale tipo indica?, non possiamo inserire elementi nella collezione In generale, non possiamo modificare valori che hanno tipo? Continua

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

Risposta Collection<Integer> ci = new ArrayList<Integer>; Colletion<?> c = ci; c.add( a string ); // non compila ci.get(0).intvalue(); L ultima istruzione invocherebbe intvalue() sul primo elemento di ci ma quell elemento ha tipo String Il compilatore previene l errore, rigettando la add()

Wilcards con vincoli (bounded) Shapes: (again!) interface Shape public void draw(graphics g); class Circle extends Shape private int x, y, radius; public void draw(graphics g)... class Rectangle extends Shape private int x, y, width, height; public void draw(graphics g)...

Wilcards con vincoli (bounded) 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 static void drawall(list<shape> shapes) for (Shape s:shapes) s.draw(this)... Solito problema: drawall() non può essere invocato su una List<Circle> Continua

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

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

Bounded Wilcards Attenzione: c è sempre un prezzo da pagare void addrectangle(list<? extends Shape> shapes) // errore di compilazione shapes.add(new Rectangle()); Non possiamo modificare strutture con questi tipi [ perché? ]

Metodi Generici

Metodi Generici Metodi che dipendono da una variabile di tipo Possono essere definiti all interno di qualunque classe, generica o meno /* trasforma un array in una lista, copiando * tutti gli elementi di a in l */ static void array2list(object[] a, List<?> l)... N.B. Evitiamo List<Object> perché renderebbe il metodo non utilizzabie su liste arbitrarie Continua

Metodi Generici Al solito però... /* trasforma un array in una lista, copiando * tutti gli elementi di a in l */ static void array2list(object[] a, List<?> l) for (Object o : a) l.add(o) // compiler error... non possiamo aggiungere elementi ad una struttura (o modificare) con elementi di tipo wildcard Continua

Metodi Generici Soluzione: rendiamo il metodo parametrico /* trasforma un array in una lista, copiando * tutti gli elementi di a in l */ static <T> void array2list(t[] a, List<T> l) for (T o : a) l.add(o) possiamo invocare questo metodo con una qualunque lista il cui tipo sia supertipo del tipo base dell array purché sia un tipo riferimento

Invocazione di metodi generici Nell invocazione di un metodo generico non è necessario passare l argomento di tipo il compilatore inferisce il tipo, se esiste, dai tipi degli argomenti del metodo

Invocazione di metodi generici Object[] oa = new Object[100]; Collection<Object> co = new ArrayList<Object>(); fromarraytocollection(oa, co); // T = Object (inferito) String[] sa = new String[100]; Collection<String> cs = new ArrayList<String>(); fromarraytocollection(sa, cs); // T = String (inferito) fromarraytocollection(sa, co); // T = Object (inferito) Integer[] ia = new Integer[100]; Float[] fa = new Float[100]; Number[] na = new Number[100]; Collection<Number> cn = new ArrayList<Number>(); fromarraytocollection(ia, cn); // T = Number (inferito) fromarraytocollection(fa, cn); // T = Number (inferito) fromarraytocollection(na, cn); // T = Number (inferito) fromarraytocollection(na, co); // T = Object (inferito) fromarraytocollection(na, cs); // compiler error Continua

Wildarcds vs variabili di tipo Ci sono situazioni in cui è possibili usare equivalentemente wildcards e variabili di tipo. Nella libreria Collection troviamo interface Collection<E> public boolean containsall(collection<?> c); public boolean addall(collection<? extends E> c);... Continua

Wildarcds vs variabili di tipo Queste specifiche possono essere espresse equivalentemente con metodi parametrici interface Collection<E> public <T> boolean containsall(collection<t> c); public <T extends E> boolean addall(collection<t> c);... Il secondo metodo è parametrico in qualunque sottotipo di E i bounds si possono utilizzare anche con variabili, non solo con wildcards Continua

Wildarcds vs variabili di tipo Wildcards e variabili di tipo possono coesistere interface Collection<E> public static <T> void copy(list<t> dest, List<? extends T> src)... Notiamo la dipendenza tra i tipi dei due parametri: il tipo della sorgente deve essere un sottotipo del tipo della destinazione Continua

Wildarcds vs variabili di tipo Potremmo analogamente riformulare in modo da evitare le wildcards interface Collection<E> public static <T, S extends T> void copy(<list<t> dest, List<S> src)... Come scegliere tra le due soluzioni? Continua

Wildarcds vs variabili di tipo In generale, preferiamo le wildcards quando entrambe le soluzioni sono possibili Possiamo darci la seguente rule of thumb se una variabile di tipo ha una unica occorrenza nella specifica di un metodo e il tipo non è il target di un operazione di modifica utilizziamo una wildcard al posto della variabile

Variabili di Tipo e Bounds Abbiamo visto che possiamo definire bounds anche per variabili di tipo (non solo wildcards) Un caso paradigmatico public static <T extends Comparable<T>> max(collection<t> coll) T candidate = coll.iterator().next(); for (T e : coll) if candidate.compareto(e) < 0) candidate = e; return candidate;

Variabili di Tipo e Bounds Il bound su una variabile impone vincoli sulla variabile, determinando quali metodi possono essere utilizzati su valori del tipo variabile public static <T extends Comparable<T>> T max(list <T> coll) Qui il bound è ricorsivo: informa che i valori con cui operiamo forniscono un metodo compareto() che gli argomenti del metodo devono essere dello stesso tipo dei valori

Generics e erasure I tipi generici sono significativi a compile-time La JVM opera invece con tipi raw Il tipo raw è ottenuto da un tipo generico mediante un processo detto erasure che rimuove le variabili di tipo il bycode generato da un tipo generico è lo stesso che viene generato dal corrispondente tipo raw.

Generics e erasure Generano lo stesso bytecode List<String> words = new ArrayList<String>(); words.add( hi ); words.add( there ); String welcome = words.get(0) + words.get(1); List words = new ArrayList(); words.add( hi ); words.add( there ); String welcome = (String)words.get(0) + (String)words.get(1);

Generics e erasure Cast-iron guarantee i cast che vengono aggiunti dalla compilazione di codice generico non falliscono mai.

Generics e Arrays In generale: A B NON implica C<A> C<B> MA: A B implica A[] B[] Quali conseguenze?

Generics e Arrays Conseguenze / 1: ArrayStoreException Integer[] ai = new Integer[10] Number[] an = ai; // type OK an[0] = 3.14; // ArrayStoreException Meglio così che continuare Integer i = ai[0]; // uh oh...

Generics e Arrays Conseguenze / 2: no new per array generici class MyClass<T> T[] contents = new T[100]; // Non compila // ecco perchè public void showtheproblem() Object[] objs = contents; objs[0] = new String(); // no ArrayStoreException T bump = contents[0]; // ClassSclassException // per T!= String

Collections