AOT LAB Agent and Object Technology Lab Dipartimento di Ingegneria dell’Informazione Università degli Studi di Parma Ingegneria del software A Collezioni di oggetti (in Java) Michele Tomaiuolo AOT LAB Framework Framework Insieme di classi che si appoggiano a delle interfacce Customizzabile: l’applicazione implementa queste interfacce per realizzare il comportamento desiderato (algoritmi) Non è l’applicazione che chiama il framework, è il framework che chiama l’applicazione Il SelectionSorter è un (piccolo) framework Sfrutta i servizi del Comparator e della List Swing è un framework 2 AOT LAB Collection framework La Java library comprende il collection framework, modulo di gestione di tipi di dato aggregati Liste Insiemi Tabelle associative Il collection framework di Java è costituito da Interfacce, che rappresentano i vari tipi dato aggregati Classi (concrete), che implementano le interfacce Algoritmi, di uso generale e definiti sui vari tipi dato Contenuto nel package java.util 3 AOT LAB Collezioni Una collezione (container) è un oggetto che raggruppa un insieme di altri oggetti Le collezioni sono usate per memorizzare e manipolare gruppi di dati Le collezioni rappresentano tipicamente oggetti che sono raggruppati per contenimento Un elenco telefonico Le parole in un vocabolario Una lista di studenti 4 AOT LAB Collection (List, Set) e Map Collection, interfaccia implementata dai dati aggregati lineari Map, interfaccia per i dati aggregati associativi Object, utilizzata per massimizzare la generalità dei dati contenuti nelle Collection e nelle Map 5 AOT LAB Interfacce e classi concrete <<interface>> 0..* Object Collection AbstractCollection <<interface>> <<interface>> Set List AbstractList ArrayList 6 AOT LAB L’interfaccia Set Un Set è una collezione non posizionale che non può contenere dati duplicati Set estende Collection e non aggiunge altri metodi Se s1 ed s2 sono entrambi Set s1.containsAll(s2), vero se s2 è sotto-insieme di s1 s1.addAll(s2), trasforma s1 nell’unione di s1 ed s2 s1.retainAll(s2), trasforma s1 nell’intersezione di s1 ed s2 7 AOT LAB L’interfaccia List Una List è un aggregato posizionale (sequenza) Una List può contenere elementi duplicati In aggiunta ai metodi di Collection Accesso posizionale get(int), set(int, Object), add(int, Object), remove(int, Object), addAll(int, Object) Ricerca indexOf(Object), lastIndexOf(Object) 8 AOT LAB Il metodo equals Insiemi e liste richiedono di poter verificare se due oggetti contenuti sono uguali Object definisce un metodo che tutto il collection framework utilizza per verificare se due oggetti sono uguali Implementazione di default: identità (riferimenti) public boolean equals(Object obj) { return (this == obj); } 9 AOT LAB Person.equals() public class Person { public boolean equals(Object o) { if (!(o instanceof Person)) return false; Person p = (Person)o; return name.equals(p.name) && familyName.equals(p.familyName); } private String name = null; private String familyName = null; } 16/Person.java 10 AOT LAB L’interfaccia Map I tipi dato associativi sono aggregati indirizzabili per “nome” anziché per posizione Dizionario, permette di accedere ad un contenuto mediante una parola Pagine bianche, permettono di accedere ad un numero di telefono mediante un nome Da utilizzare con cautela: non possono sostituire le relazioni tra gli oggetti 11 AOT LAB Uso dell’intefaccia Map import java.util.Map; import java.util.HashMap; public class Main { public static void main(String[] args) { Person person = new Person("Paolo", "Rossi"); Passport passport = new Passport(12345); person.setPassport(passport); passport.setPerson(person); Map passports = new HashMap(); passports.put(person, passport); Passport p = (Passport)passports.get(person); if (p == null) { System.out.println("…"); } else { System.out.println("…" + p.getNumber()); } } } 16/Main.java 12 AOT LAB Il metodo hashCode Map efficiente: possibile utilizzare un codice hash (numero intero) associato ad ogni oggetto contenuto Se due oggetti sono uguali (secondo equals) Allora hanno lo stesso codice hash Se si implementa equals, bisogna implementare hashCode Se due oggetti non sono uguali (secondo equals) Dovrebbero avere codice hash diverso Questo è preferibile, ma non è necessario Una tabella hash sfrutta i codici hash degli oggetti contenuti per velocizzare l’indirizzamento L’hash serve come indirizzo virtuale (non univoco) del contenuto 13 AOT LAB Person.hashCode() public class Person { public boolean equals(Object o) { if(!(o instanceof Person)) return false; Person p = (Person)o; return name.equals(p.name) && familyName.equals(p.familyName); } public int hashCode() { return (name + familyName).hashCode(); } private String name = null; private String familyName = null; } 16/Person.java 14 AOT LAB Implementazioni Il collection framework mette a disposizione più implementazioni per ogni interfaccia Map: HashMap e TreeMap List: ArrayList e LinkedList Set: TreeSet e HashSet Conviene sempre riferirsi alle classi concrete solo al momento della creazione dell’oggetto List list = new ArrayList() 15 AOT LAB Iteratori Tutto il collection framework utilizza un unico modo per accedere agli singoli elementi dei tipi dato aggregati Iteratore: oggetto che permette di accedere agli elementi di un tipo dato aggregato secondo un certo ordine Vengono creati dal tipo dato aggregato La politica di attraversamento viene cambiata cambiando la classe dell’iteratore 16 AOT LAB ListIterator <<interface>> <<interface>> Collection Iterator + iterator() : Iterator <<interface>> - ListForwordIterator List AbstractList <<creates>> ArrayList return new ListForwardIterator(this); + iterator() : Iterator 17 AOT LAB ArraySet public class ArraySet implements Set, Cloneable { // … private class ArraySetIterator implements Iterator { public Object next() { if (current == collection.size) throw new NoSuchElementException(); return collection.buffer[current++]; } public boolean hasNext() { return current < collection.size; } public void remove() { throw new UnsupportedOperationException(); } private ArraySetIterator(ArraySet set) { collection = arraySet; } private int current = 0; private ArraySet collection = null; } } 17/ArraySet.java 18 AOT LAB Scorrere una collezione 1. Si usa esplicitamente il suo iteratore: for (Iterator i = collection.iterator(); i.hasNext(); ) { Object item = i.next(); } 2. Oppure si usa il for (Java 5): Collection collection = … for (Object item : collection) { // … } int[] vals = {1, 2, 3, 4}; for (int x : vals) { // … } 19 AOT LAB Copia di un oggetto L’operatore di assegnamento copia le reference tra gli oggetti (shallow copy) A obj2 = obj1; obj2 e obj1 puntano allo stesso oggetto Object fornisce un metodo clone() Effettua la copia di tutte le proprietà e le associazioni (shallow) Ma l’oggetto deve implementare Cloneable Altrimenti viene lanciata CloneNotSupportedException A obj2 = obj1.clone(); obj2 e obj1 sono due copie distinte dello stesso oggetto 20 AOT LAB Shallow vs. deep copy Shallow copy Si ottengono due riferimenti allo stesso oggetto Anche il metodo clone() di default (di Object) può essere definito shallow (copia i riferimenti delle associazioni) Deep copy L’oggetto copia è una struttura completamente separata dall’originale Implementazione custom di clone() 21 AOT LAB Classe Person Per oggetti complessi può essere necessario implementare clone() Nel caso di Person, l’implementazione coincide con quella di default Esercizio: associazione (es. children) con altri oggetti Person public class Person { public Object clone() { return new Person(name, familyName); } private String name = null; private String familyName = null; } 16/Person.java 22 AOT LAB Liste e cast Java 1.4 (Senza generics) class Mem { private List list = new ArrayList(); public void push(Object o) { list.add(o); } public Object pop() { return list.remove(list.size() - 1); } } Mem m = new Mem(); m.push("Something"); String s = (String) m.pop(); // cast... 23 AOT LAB Generics Java 1.5 (con generics) Mem<String> m1 = new Mem<String>(); m1.push("Something"); String a = m1.pop(); // no cast Mem<Integer> m2 = new Mem<Integer>(); m2.push(7); // autoboxing: m.push(new Integer(7)); int i = m2.pop(); // auto-unboxing: i = m.pop().intValue() class Mem<E> { private List<E> list = new ArrayList<E>(); public void push(E item) { list.add(item); } public E pop() { return list.remove(list.size() - 1); } } 24