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