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