Muoversi all interno di un Vector 4 Vector e Enumeration Attraversare la collezione di oggetti e visitare (elaborare) ciascun elemento 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 Operazioni caratteristiche Creare una nuova collezione (costruttore) Aggiungere un oggetto ad una collezione Elaborare gli oggetti della collezione Java fornisce diverse classi collezione Contenute nel package java.util La più semplice classe collezione è la classe Vector Creazione: Vector v = new Vector(); Enumeration Java offre una classe Enumeration che modella l attraversamento 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 La classe Vector contiene un metodo, elements, che restituisce un riferimento ad un oggetto Enumeration Enumeration elements() { // Restituisce un Enumeration per Vector Enumeration fornisce i seguenti metodi boolean hasmoreelements() // Restituisce true se ci sono altri elementi da // visitare; restituisce false altrimenti Object nextelement() //Rrestituisce un riferimento all elemento successivo 3 6 v 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 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à Vector v = new Vector(); v.addelement(s); Più applicazioni di addelement
7 10 Lavoro supplementare Il prezzo da pagare per tale flessibilità: 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 Il Costruttore 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); 8 11 Il ciclo di attraversamento Il ciclo di attraversamento di una collezione 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); Il metodo lookup 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()); 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; 9 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)); // altri inserimenti di interi nel Vector vi // Include il valore int // all interno di un oggetto Integer
Visitare dati di tipi primitivi di una collezione Per la visita invece: 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 Lo stesso vale per i costruttori delle altre classi involucro (Boolean, Float, Double) 13 Determinazione del comportamento Ovviamente abbiamo un costruttore 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 16 Determinare i risultati di uno studente 14 Definizione dell interfaccia 17 Si supponga di avere un file del registro degli studenti di un corso universitario. Per ogni studente il file contiene la coppia di linee: nome media Vogliamo stabilire quali studenti siano sopra e quali sotto la media della classe Utilizzo dei metodi StudentRoster roster = new StudentRoster( CS1.f98 ); roster.evaluate(); L interfaccia class StudentRoster { StudentRoster(String rosterfilename) { void evaluate() { 15 18 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 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)
19 22 Definizione delle variabili d istanza (2) class StudentRoster { public StudentRoster(String rosterfilename) { pblic void evaluate() { private Vector studentcoll; private int classaverage; Uso della classe 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(); 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 Implementazione del costruttore Una classe insieme Una classe collezione che chiameremo Set Determinazione del comportamento Set Costruttore contains test di appartenenza isempty verifica dell insieme vuoto null addelement aggiunge un elemento a un Set copy fa una copia di un Set size restituisce il numero di elementi di un Set elements restituisce una Enumeration per l attraversamento union genera l unione di due Set intersection genera l intersezione di due Set print stampa l insieme 23 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"); 21 Set s1, s2; s1 = new Set(); s2 = s1; s1 Il metodo copy 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 s2 Oggetto Set 24
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()); 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); Definizione dell interfaccia: Esempio di codice d uso // il metodo tostring trasforma un oggetto in String 25 Implementazione dei metodi (1) public Set() { vector = new Vector(); public boolean isempty() { return vector.isempty(); public int size() { return vector.size(); public Enumeration elements() { return vector.elements(); 28 26 29 Definizione dell interfaccia 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(); 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 30 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; 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(); while (enum.hasmoreelements()) unionset.addelement(enum.nextelement()); return unionset;
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 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; 31 Il metodo tostring funziona bene se l oggetto è di una classe predefinita, come ad esempio Integer 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()); Il metodo tostring della classe Object (1) Per una classe definita dall utente invece, poiché il metodo tostring non sa nulla sulla classe effettiva, viene prodotta una stringa con poche informazioni. 34 Implementazione dei metodi (5) public boolean contains(object o) { 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) 32 Il metodo tostring della classe Object (2) 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 35 Implementazione dei metodi (6) public void print(printstream ps) { 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) 33 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 36
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; 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 38