Collezioni di oggetti - Università degli Studi di Parma

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