Vector e Enumeration Collezioni di oggetti: Vector Aggiungere

Transcript

Vector e Enumeration Collezioni di oggetti: Vector Aggiungere
4
Muoversi all’interno di un Vector
Attraversare la collezione di oggetti e visitare (elaborare)
ciascun elemento
Vector e Enumeration
– E’ un processo ripetitivo e quindi viene usata una struttura di ciclo
while(ci sono ancora elementi da visitare)
visitare l’elemento successivo
Per poter visitare tutti gli elementi di un Vector è necessario:
– Raggiungere in qualche modo gli elementi
– Ottenere l’elemento successivo
– Verificare se ci sono altri elementi da visitare
La classe Vector non fornisce questi metodi …
2
5
Collezioni di oggetti: Vector
Enumeration
Java offre una classe Enumeration che modella l’attraversamento
Operazioni caratteristiche
– In realtà non si tratta proprio di una classe
– Ogni classe collezione fornisce un metodo che crea e restituisce un riferimento a
un oggetto della classe Enumeration
– L’oggetto Enumeration fornisce i metodi per ottrenere l’elemento successivo e
verificare se ci sono altri elementi
– Creare una nuova collezione (costruttore)
– Aggiungere un oggetto ad una collezione
– Elaborare gli oggetti della collezione
Java fornisce diverse classi collezione
La classe Vector contiene un metodo, elements, che restituisce un
riferimento ad un oggetto Enumeration
– Contenute nel package java.util
– Enumeration elements() {…} // Restituisce un Enumeration per Vector
La più semplice classe collezione è la classe Vector
– Creazione:
Enumeration fornisce i seguenti metodi
– boolean hasMoreElements()
Vector v = new Vector();
– Object nextElement()
// Restituisce true se ci sono altri elementi da
// visitare; restituisce false altrimenti
//Rrestituisce un riferimento all’elemento successivo
3
Aggiungere oggetti a un Vector
Leggiamo alcuni oggetti String e aggiungiamoli al Vector v
String s;
s = br.readline(); // Legge la prima stringa
while (s != null) {
v.addElement(s);
// Elaborazione: aggiunge s a v
s = br.readline();
// Legge la stringa successiva
}
v
v
v
Vector v = new Vector();
v.addElement(s);
6
La classe Object
nextElement restituisce un riferimento ad un oggetto di
classe Object
La classe predefinita Object modella un qualsiasi oggetto
– I riferimenti a Name, Employee, String, ecc. sono anche riferimenti
a Object
In questo modo nextElement può restituire riferimenti a
oggetti di qualsiasi classe
– C’è un prezzo da pagare per questa flessibilità …
Più applicazioni di addElement
1
7
Lavoro supplementare
10
Il Costruttore
Il prezzo da pagare per tale flessibilità:
public SongLibrary(String songFileName) throws Exception {
songColl = new Vector();
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream (songFileName)));
Song song = Song.read(br);
while(song != null) {
songColl.addElement(song);
song = Song.read(br);
}
}
– Effettuare un’operazione di cast davanti ad ogni invocazione di
nextElement
Name n = new Name(“Gerald”, “Weiss”);
Vector v = new Vector();
v.addElement(n);
Enumeration e = v.elements(); // trasforma un Vector in una Enumeration
Name n2 = (Name) e.nextElement(); // nextElement restituisce un riferimento
// ad Object che viene trasformato in un
cast
// riferimento a Name mediante cast
– Assicurarsi che in ogni oggetto Vector si aggiungono riferimenti ad
un solo tipo di oggetto
8
Il ciclo di attraversamento
11
Il metodo lookUp
Il ciclo di attraversamento di una collezione
public void lookUp(String artist) {
Enumeration enum = songColl.elements();
while(enum.hasMoreElements()) {
Song song = (Song) enum.nextElement();
if (artist.equals(song.getArtist()))
System.out.println(song.getTitle());
}
}
Enumeration enum = ottenere un riferimento Enumeration dalla collezione
while(enum.hasMoreElements()) {
ClassName x = (ClassName) enum.nextElement(); // Estrae gli elementi
elaborare x
}
Un esempio: stampiamo le String di un Vector
Enumeration enum = v.elements();
while(enum.hasMoreElements()) {
String s = (String) enum.nextElement();
System.out.print(s);
}
9
Rivisitiamo la classe SongLibrary
Miglioriamo l’implementazione lasciando inalterata
l’interfaccia.
– Il contenuto del file viene caricato in un Vector dal costruttore
– Il metodo lookUp attraverserà la collezione
import java.io.*;
import java.util.*; // perché stavolta usiamo un Vector
class SongLibrary {
public SongLibrary(String songFileName) throws Exception {...}
void lookUp(String artist) {...}
// Variabili di istanza
private Vector songColl;
}
12
Inserire dati di tipi primitivi
in una collezione
In un Vector è possibile inserire oggetti (Object)
– int, float, ecc. non sono oggetti, ma tipi primitivi
– Per risolvere questo problema si può ricorrere alle “classi
involucro” (Integer, Boolean, Float, …)
Ad esempio, per gli interi:
Vector vi = new Vector();
int i;
i = 1;
vi.addElement(new Integer(i));
// Include il valore int
// all’interno di un oggetto Integer
… // altri inserimenti di interi nel Vector vi
2
13
16
Visitare dati di tipi primitivi
di una collezione
Determinazione del comportamento
Per la visita invece:
Ovviamente abbiamo un costruttore
Enumeration e = vi.elements();
while(e.hasMoreElements()) {
Integer integer = (Integer) e.nextElement(); // estrae l’oggetto
System.out.println(integer.intValue()); // stampa il valore intero
}
Da notare che il costruttore della classe Integer accetta
come argomento un int
– StudentRoster
E un metodo che percorre il registro e valuta gli
studenti (ci dice se stanno sopra o sotto la media)
– evaluate
Non è stato ancora detto quando di intende
calcolare la media, né se si userà una collezione
– Questi aspetti riguardano l’implementazione dei
metodi e la definizione delle variabili d’istanza
– Lo stesso vale per i costruttori delle altre classi involucro
(Boolean, Float, Double)
14
17
Determinare i risultati
di uno studente
Definizione dell’interfaccia
Si supponga di avere un file del registro degli
studenti di un corso universitario.
Per ogni studente il file contiene la coppia di
linee:
Utilizzo dei metodi
StudentRoster roster = new StudentRoster(“CS1.f98”);
roster.evaluate();
L’interfaccia
nome
media
class StudentRoster {
StudentRoster(String rosterFileName) { … }
void evaluate() {… }
Vogliamo stabilire quali studenti siano sopra e quali sotto
la media della classe
}
15
Determinazione dell’oggetto primario
Candidati: file del registro, studente, nome e
media
– Nome e media sono subordinati a studente che a sua
volta è subordinato a file del registro
Introduciamo la classe StudentRoster, associata
al file d’ingresso
– Notare l’analogia con la classe SongLibrary
– In entrambi i casi gli oggetti subordinati sono letti dal
file associato all’oggetto primario
18
Definizione delle variabili d’istanza (1)
Occorre valutare la media della classe
– Può essere fatto dal costruttore e l’informazione può
essere mantenuta in una variabile d’istanza (in tal
modo può essere usata dal metodo evaluate)
Le informazioni relative agli studenti sono
richieste due volte:
– Per calcolare la media (nel costruttore)
– Per valutare gli studenti (nel metodo evaluate)
– Conviene usare una variabile di istanza (una
collezione)
3
19
22
Uso della classe
Definizione delle variabili d’istanza (2)
class Evaluator {
public static main(String[] args) throws Esception {
StudentRoster roster1 = new StudentRoster(“CS1.f98”);
roster1.evaluate();
StudentRoster roster2 = new StudentRoster(“CS2.f98”);
roster2.evaluate();
}
class StudentRoster {
public StudentRoster(String rosterFileName) { … }
pblic void evaluate() {… }
private Vector studentColl;
private int classAverage;
Considerazioni conclusive
– Occorre costruire la classe Student (farlo come esercizio …)
– Possibili diverse implementazioni (ad esempio, scorrere più volte il
file invece di mantenere la collezione in memoria) …
– in pratica un file non è altro che una collezione residente su disco
}
public StudentRoster(String rosterFileName)
throws Exception {
studentColl = new Vector();
BufferedReader br =
new BufferedReader(
new InputStreamReader(
new FileInputStream(rosterFileName)));
int total = 0;
// somma le medie
int count = 0;
// conta gli studenti
Student student = Student.read(br); // introduzione della classe Student
while (student != null) {
// struttura di ciclo lettura/elaborazione
total += student.getAverage();
count++;
studentColl.addElement(student);
student = Student.read(br);
}
classAverage = total / count;
}
20
23
Implementazione
del costruttore
Una classe insieme
Una classe collezione che chiameremo Set
Determinazione del comportamento
–
–
–
–
–
–
–
–
–
–
Set
contains
isEmpty
addElement
copy
size
elements
union
intersection
print
Costruttore
test di appartenenza
verifica dell’insieme vuoto null
aggiunge un elemento a un Set
fa una copia di un Set
restituisce il numero di elementi di un Set
restituisce una Enumeration per l’attraversamento
genera l’unione di due Set
genera l’intersezione di due Set
stampa l’insieme
21
24
Implementazione di evaluate
public void evaluate() {
Enumeration enum = studentColl.elements();
while (enum.hasMoreElements()) { // struttura di ciclo enumerare
Student student = (Student)enum.nextElement();
System.out.print(student.getName());
System.out.print(" is performing ");
if (student.getAverage() >= classAverage)
System.out.println("above average");
else
System.out.println("below average");
}
}
Il metodo copy
Set s1, s2;
s1 = new Set();
…
s2 = s1;
s1
s2
Oggetto Set
Notare che con l’assegnamento le due variabili s1 e s2 fanno riferimento
allo stesso oggetto
– i cambiamenti apportati ad s1 si ripercuotono su s2 e viceversa
Noi vogliamo che il metodo copy crei un nuovo oggetto Set e copi gli
elementi del vecchio insieme nel nuovo
s1
s2
Oggetto Set
Oggetto Set
4
25
Definizione dell’interfaccia:
Esempio di codice d’uso
28
Implementazione dei metodi (1)
Class UseSet {
public static main(String[] args) {
Set s1 = new Set();
s1.addElement(“A”);
s1.addElement(“B”);
s1.addElement(“C”);
s1.addElement(“A”);
System.out.println(s1.toString()); // il metodo toString trasforma un oggetto in String
Set s2 = new Set();
s2.addElement(“B”);
s2.addElement(“C”);
s2.addElement(“D”);
s2.addElement(“D”);
s2.print(System.out);
s1.union(s2).print(System.out);
s1.intersection(s2).print(System.out);
}
public Set() {
vector = new Vector();
}
public boolean isEmpty() {
return vector.isEmpty();
}
public int size() {
return vector.size();
}
public Enumeration elements() {
return vector.elements();
}
26
Definizione dell’interfaccia
29
Implementazione dei metodi (2)
Class Set {
public Set () { … }
public boolean contains(Object o) { … }
public boolean isEmpty() { … }
public void addElement(Object o) { … }
public Set copy() { … }
public int size() { … }
public Enumeration elements() { … }
public Set union(Set s) { … }
public Set intersection(Set s) { … }
public void print(PrintStream ps) { … }
}
// notare il parametro Object usato per garantire la genericità
// rispetto agli oggetti contenuti in un Set
public Set copy() {
Set destSet = new Set();
Enumeration enum = vector.elements();
while (enum.hasMoreElements())
destSet.addElement(enum.nextElement());
return destSet;
}
public void addElement(Object o) {
if (!contains(o)) // si aggiunge solo se non è già presente
vector.addElement(o);
}
27
Definizione delle variabili di istanza
Un set contiene un numero arbitrario di elementi, per cui è
richiesta una collezione
Per la collezione scegliamo la classe Vector (è l’unica che
conosciamo)
Class Set {
… // Metodi
private Vector vector;
}
30
Implementazione dei metodi (3)
Per l’unione il Set restituito si costruisce copiando prima gli
elementi del Set argomento e poi aggiungendo gli elementi
del Set ricevente
public Set union(Set s) {
Set unionSet = s.copy();
Enumeration enum = vector.elements();
while (enum.hasMoreElements())
unionSet.addElement(enum.nextElement());
return unionSet;
}
5
31
34
Il metodo toString della
classe Object (1)
Implementazione dei metodi (4)
Per l’intersezione il Set restituito si costruisce aggiungendo gli elementi
del Set ricevente che sono anche contenuti nel Set argomento
Il metodo toString funziona bene se l’oggetto è di una classe
predefinita, come ad esempio Integer
public Set intersection(Set s) {
Set interSet = new Set();
Enumeration enum = this.vector.elements();
while (enum.hasMoreElements()) {
Object elem = enum.nextElement();
if (s.contains(elem))
interSet.addElement(elem);
}
return interSet;
}
– Il numero 275 contenuto in un oggetto di classe Integer viene
trasformato nella stringa “275”:
Integer i = new Integer(275);
System.out.print(i.toString());
Per una classe definita dall’utente invece, poiché il metodo
toString non sa nulla sulla classe effettiva, viene prodotta una
stringa con poche informazioni.
32
35
Il metodo toString della
classe Object (2)
Implementazione dei metodi (5)
public boolean contains(Object o) {
Enumeration enum = vector.elements();
while (enum.hasMoreElements()) {
Object elem = enum.nextElement();
if (elem.equals(o))
return true;
}
return false;
}
Il metodo equals della classe Object non funziona in modo
soddisfacente … (vedremo dopo una soluzione al problema)
Ad esempio per la classe
class Test {
public Test () { // la classe non ha né comportamento, né stato }
}
Applichiamo toString ad un oggetto Test
Test t = new Test();
System.out.print(t.toString());
Viene invocato il metodo toString della classe Object
Il risultato in uscita è una stringa della forma Test@15368
33
Implementazione dei metodi (6)
public void print(PrintStream ps) {
Enumeration enum = vector.elements();
while (enum.hasMoreElements()) {
ps.print(enum.nextElement().toString());
ps.print(" ");
}
}
Il metodo toString produce una stringa a partire da un oggetto,
consentendo quindi la stampa dell’oggetto (come vedremo anche
questo metodo non è proprio soddisfacente)
36
Il metodo toString della
classe Object (3)
Se vogliamo un comportamento diverso dobbiamo
personalizzare il metodo toString scrivendone uno
che ha lo stesso prototipo di quello della classe
Object
– public String toString() { … }
Questo approccio è noto con il termine overriding
– Sovrascriviamo il metodo pre-esistente con uno nuovo
6
37
Esempi di metodi toString
Un metodo toString per la classe Test
class Test {
public Test () { }
public String toString() { return “I am a Test object”; }
}
Un metodo toString per la classe Name
class Name {
…
public String toString() {
String result = this.title + “ “ + this.firstName + “ “ + this.lastName;
return result;
}
}
38
Un metodo toString
per la classe Set
public String toString() {
String result = “{“;
Enumeration e = elements();
while(e.hasMoreElements()) { // struttura ciclo enumerare
result += e.nextElement().toString();
result += “ ”;
}
result += “}“;
return result;
}
In alternativa si può usare il metodo toString della classe Vector
public String toString() {
return vector.toString(); // vector è la variabile di istanza
}
7