Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 2 Dispensa E08 Esercizi su I/O e classe Object F. Gasparetti Marzo 2007 http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 1 Contenuti I metodi equals e clone di Object Dato un file di testo su hard drive: Leggere il contenuto del file Memorizzarne il contenuto del file in una lista di stringhe Visualizzare il contenuto della lista su schermo Salvare il contenuto della lista su un secondo file Dati due file di testo su hard drive, confrontarne il contenuto http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 2 Il metodo equals di Object . . . Il metodo equals è definito nella classe Object è ritorna true se il parametro è “uguale” all’oggetto su cui si invoca. public boolean equals(Object obj) Ma che significa uguale? Object fornisce una implementazione di default che viene ereditata per ogni classe Java, a meno che non venga ridefinita dal programmatore Il metodo di default implementa una uguaglianza superficiale tra gli argomenti . . . http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 3 Uguaglianza superficiale L’implementazione di default di Object è la seguente: ∀x, y ≠ null, x.equals(y)=true sse x e y referenziano lo stesso oggetto in memoria, ovvero è verificata la condizione x == y L’uguaglianza superficiale non è adatta se quello che vogliamo confrontare è il valore rappresentato da due oggetti, anche distinti: Terna x = new Terna(5, 3, 1); Terna y = new Terna(5, 3, 1); Terna z = x; x.equals(z) ⇒ true x.equals(y) ⇒ false // ATTENZIONE http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 4 Uguaglianza superficiale Immaginiamo una classe Insieme che mantiene una collezione di oggetti “distinti” Possiamo pensare di mantenere l’implementazione di default di equals e memorizzare una serie di Terne, ma in questo caso le due terne x e y vengono memorizzate come due oggetti distinti: Terna x = new Terna(5, 3, 1); Terna y = new Terna(5, 3, 1); Nel nostro insieme vogliamo istanze che rappresentano valori distinti le une dalle altre http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 5 Uguaglianza profonda Se vogliamo confrontare i valori rappresentati dagli oggetti (uguaglianza profonda), dobbiamo fornire una implementazione ad hoc per ogni classe che andiamo a definire Occorre individuare quali sono le variabili all’interno della classe che rappresentano l’oggetto e farne il confronto http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 6 Esempio: equals nella classe Terna public class Terna { . . . public boolean equals(Object o) { boolean ret = false; // se l’oggetto o appartiene a una classe diversa // rispetto a this, i due oggetti non possono // essere uguali if (o == null || !getClass().equals(o.getClass())){ ret = false; } else { Terna t = (Terna)o; // nuova condizione di uguaglianza if (t.riga == riga && t.colonna == colonna) ret = true; } return ret; } } http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 7 Il metodo equals di Object . . . Alcune classi Java ridefiniscono il metodo equals in modo opportuno: String.equals() = true se le due stringhe rappresentano la stessa sequenza di caratteri Integer.equals() = true se i due oggetti Integer rappresentano lo stesso valore ... http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 8 . . .Il metodo equals di Object Una implementazione di equals deve essere conforme ad una relazione di equivalenza: ∀x ≠ null, x.equals(x) = true (riflessiva) ∀x, y ≠ null, x.equals(y) = true sse y.equals(x) = true (simmetrica) ∀x, y, z ≠ null, x.equals(y) = true e y.equals(z) = true allora x.equals(z) = true (transitiva) ∀x, y ≠ null, due o più invocazioni di x.equals(y) devono ritornare lo stesso valore nel caso in cui nessuna variabile di x e y venga alterata tra le invocazioni ∀x ≠ null, x.equals(null) = false http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 9 Problemi di memoria condivisa . . . Lo schema realizzativo con condivisione di memoria può risultare fonte di errori nel caso in cui si utilizzino strutture dinamiche (ad esempio Liste) che collegano oggetti che vengono modificati durante l’esecuzione. Se un oggetto è condiviso da due strutture, aggiornamenti su una struttura possono influenzare anche l’altra http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 10 . . .Problemi di memoria condivisa . . . public class MemoriaCondivisa { . . . public static void main(String[] args) { Lista l1, l2; l1 = new Lista(); l2 = new Lista(); Terna t1 = new Terna(1,2,3); Terna t12 = new Terna(2,3,4); Terna t13 = new Terna(3,4,5); Terna t22 = new Terna(4,5,6); Terna t23 = new Terna(5,6,7); . . . http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 11 . . .Problemi di memoria condivisa . . . l1 = l1.cons(t13); l1 = l1.cons(t12); l1 = l1.cons(t1); l2 = l2.cons(t23); l2 = l2.cons(t22); l2 = l2.cons(t1); System.out.println("l1:\n"+l1.toString()); System.out.println("l2:\n"+l2.toString()+"\n"); Terna t = (Terna)l1.car(); t.riga++; t12.riga++; System.out.println("l1:\n"+l1.toString()); System.out.println("l2:\n"+l2.toString()); } } http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 12 . . .Problemi di memoria condivisa . . . La terna t1 viene condivisa tra l1 e l2 l1 NodoLista NodoLista info info t1 t12 NodoLista info t13 next next NodoLista NodoLista NodoLista info info next Terna t1 riga colonna valore l2 t1 next http://www.dia.uniroma3.it/~java/fondinf2/ t22 next Esercizi su I/O e Object info t23 next 13 . . .Problemi di memoria condivisa . . . Output del programma: elementi l1: 123 234 345 elementi l2: 123 456 567 elementi l1: 223 334 345 elementi l2: 223 456 567 La modifica del primo elemento di l1 ha influenzato anche l2; comportamento generalmente scorretto La modifica di t12 ha influenzato correttamente solo l1 http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 14 . . .Problemi di memoria condivisa . . . Per risolvere il problema ci sono due soluzioni: 1. Creare istanze diverse degli oggetti (anche se rappresentano gli stessi dati) prima di inserirli nelle strutture dinamiche: // Terna t1 = new Terna(1,2,3) Terna t11 = new Terna(1,2,3); Terna t12 = new Terna(1,2,3); . . . l1 = l1.cons(t11); l2 = l2.cons(t12); http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object NO!! 15 . . .Problemi di memoria condivisa . . . 2. Richiamare il metodo clone per creare una copia degli oggetti prima dell’inserimento: Terna t1 = new Terna(1,2,3); Terna t12 = (Terna)t1.clone(); . . . l1 = l1.cons(t1); l2 = l2.cons(t12); http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 16 . . .Problemi di memoria condivisa . . . Il metodo clone deve essere definito all’interno della classe le cui istanze non possono essere condivise tra due o più oggetti Il metodo deve creare un oggetto dello stesso tipo dell’oggetto originale ma indipendente, e copiare le variabili dall’oggetto originale nel nuovo oggetto Le variabili che non possono essere condivise (come strutture dinamiche annidate) devono essere a loro volta soggetto di clonazione http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 17 . . .Problemi di memoria condivisa. . . Se una classe contiene solo tipi primitivi (int, boolean, etc) o riferimenti a oggetti che non vengono mai modificati, si può sfruttare l’implementazione di default di clone, che alloca spazio per il nuovo oggetto e si occupa di copiare tutte le variabili primitive La signatura di clone in Object è: protected Object clone() throws CloneNotSupportedException ma può essere ridefinito public se occorre http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 18 Esempio: clone nella classe Terna public class Terna implements Cloneable { . . . public Object clone() throws CloneNotSupportedException { // richiamo l’implementazione di default che crea // un nuovo oggetto Terna e copia i dati primitivi; // Object.clone è protetto, ma Terna estende implicitamente // Object perciò posso richiamare clone di Object. Terna t = (Terna)super.clone(); // qui copio i dati non primitivi se esistono. ... // le istruzioni che seguono sono inutili perché se ne // occupa super.clone(); // t.riga = this.riga; // t.colonna = this.colonna; // t.valore = this.valore; return t; } } http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 19 . . .Problemi di memoria condivisa Ora clone è stato ridefinito con visibilità public, perciò possiamo richiamarlo ovunque all’interno del nostro codice: Terna t1 = new Terna(1,2,3); // ora la chiamata è corretta Terna t12 = (Terna)t1.clone(); Quando si definisce clone all’interno di una classe C, occorre aggiungere l’interfaccia Cloneable nella definizione di C: public class Terna implements Cloneable http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 20 Esercizio Implementare il metodo clone per la classe Lista, sia nel caso in cui NodoLista contenga il campo info di tipo String, sia nel caso info sia di tipo Object. http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 21 Esercizio Che cosa stampa il seguente frammento di codice? abstract class PersonaAbstract implements Cloneable { protected String nome = new String("PersonaAbstract"); public abstract void setXY(); public String getNome() { return nome; } public Object clone() throws CloneNotSupportedException { PersonaAbstract p = (PersonaAbstract)super.clone(); p.nome = p.nome + "; PersonaAbstract dopo clone"; return p; } } . . . http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 22 Esercizio class Studente extends PersonaAbstract { public void setXY() { return; } public Object clone() throws CloneNotSupportedException{ Studente s = (Studente)super.clone(); s.nome = s.nome + "; Studente dopo clone"; return s; } } public class CloneExample { public static void provaClonePA(PersonaAbstract p) { System.out.println("provaClonePA: "+p.getNome()); } . . . http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 23 Esercizio public static void main(String[] args) throws Exception { Studente s = new Studente(); Studente sclone = (Studente)s.clone(); provaClonePA(s); provaClonePA(sclone); } } http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 24 Gestioni di file in Java I/O Java: Un gruppo di classi organizzate mediante ereditarietà e basate su streams che rendono meno complicata la lettura e scrittura di vari tipi di dati su file: file di testo: sono documenti, cioè sequenze di caratteri tipicamente stampabili e interpretabili dall’utente che possono essere generati da un editor di testi file binario: contengono informazioni interpretabili solo da un programma specifico, ad esempio il file Excel “tesina.xls” http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 25 Gli Stream Uno stream è una struttura logica che permette di leggere o scrivere sequenze di dati serialmente, uno dopo l’altro, su varie sorgenti di dati (file, stringhe, buffer, etc). Se trattiamo caratteri e stringhe usiamo la famiglia di classi Reader/Writer (characterbased I/O) per gli altri tipi di oggetti usiamo la famiglia di classi InputStream/OutputStream (byte-oriented I/O) http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 26 Classi derivate da Reader/Writer Alcuni tipi di Reader: FileReader: stream che legge caratteri da file CharArrayReader: uno stream in lettura da un array di char StringReader: uno stream in lettura da una stringa Alcuni tipi di Writer: FileWriter: uno stream che scrive caratteri su file CharArrayWriter: StringWriter: uno stream che colleziona l’output verso un oggetto String PrintWriter: stampa in modo formattato caratteri, stringhe ed altri oggetti su uno stream di output http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 27 Le Classi I/O e l’ereditarietà Le classi Reader hanno il metodo read() per leggere rispettivamente singoli byte e caratteri da un File. Ogni classe che deriva da queste due classi eredita il metodo read ed eventualmente implementa ulteriori metodi Reader → read() FileReader → read() . . . CharArrayReader → read() http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object BufferedReader → read() → readLine() 28 Gli streams di input e output standard In Java la console e la tastiera sono trattati come particolari stream rispettivamente di output e input: Class System { public static final PrintStream out; public static final InputStream in; . . . } System.out.println(“scrivo su stream”); http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 29 Composizione di Streams Molte volte per leggere o scrivere dati componiamo più streams insieme, dove l’output di uno e preso come input dal successivo: myFile.txt // apertura del file in lettura FileReader fr = new FileReader(“myFile.txt”); // lettura bufferizzata dallo stream fr BufferedReader br = BufferedReader(fr); String s = br.readLine(); http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 30 Esercizio: file di testo . . . Dato un file di testo su hard drive: 1. Leggere il contenuto del file 2. Memorizzarne il contenuto del file in una lista di stringhe 3. Visualizzare il contenuto della lista su schermo 4. Salvare il contenuto della lista su un secondo file Sfruttiamo le seguenti librerie e classi: 1. 2. 3. 4. Java I/O: streams di input (classi Reader) Classe Lista (vedi dispense strutture collegate) Java I/O: stream di output (classe PrintStream) Java I/O: streams di output (classi Writer) http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 31 . . . Esercizio: file di testo . . . Realizziamo una classe StringIO dove esistono tre metodi: leggiFile: dato un nome (e percorso) di un file, carica il contenuto all’interno di una struttura collegata scriviFile: dato un nome (e percorso) di un file, scrive il contenuto della struttura collegata sul file stampa: visualizza su schermo il contenuto della struttura collegata http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 32 Riprendiamo il NodoLista. . . La classe NodoLista per le liste di stringhe: class NodoLista { public String info; public NodoLista next; . . . } Supponiamo di avere disponibili le classi NodoLista e ListaUso che avevamo definito precedentemente. http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 33 . . . Esercizio: file di testo . . . import java.io.*; public class StringIO { public static Lista leggiFile(String filename) throws IOException { Lista contenutoFile = new Lista(); // apro il file in lettura FileReader reader = new FileReader(filename); // BufferedReader per leggere una riga alla volta BufferedReader br = new BufferedReader(reader); String linea = null; . . . http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 34 . . . Esercizio: file di testo . . . // lettura da file una linea alla volta while ((linea = br.readLine()) != null) { // ListaUso per inserire in coda contenutoFile = ListaUso.aggiungiUltimo (linea, contenutoFile); } // chiudo tutti gli stream br.close(); reader.close(); return contenutoFile; } public void stampa(Lista l) throws IOException { . . . http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 35 . . . Esercizio: file di testo . . . while (!l.estVuota()) { String linea = (String)l.car(); // elimino la testa della lista l = l.cdr(); System.out.println(linea); } } public static void scriviFile(Lista l, String filename) throws IOException { // apro il file in scritto (se esiste lo sovrascrivo) FileWriter writer = new FileWriter(filename); // BufferWriter per scrivere una stringa su file BufferedWriter bw = new BufferedWriter(writer); . . . http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 36 . . . Esercizio: file di testo . . . . . . while (!l.estVuota()) { String linea = (String)l.car(); l = l.cdr(); bw.write(linea+”\n”); } // chiudo gli streams bw.close(); writer.close(); } http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 37 . . . Esercizio: file di testo . . . public static void main(String[] args) throws IOException { try { Lista l = StringIO.leggiFile("email.txt"); System.out.println ("--> stampo il contenuto del file <--"); StringIO.stampa(l); StringIO.scriviFile(l, "email1.txt"); } catch(Exception ex) { System.out.println(ex.toString()); ex.printStackTrace(); System.exit(1); } System.out.println("--> fine senza errori <--"); } } http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 38 Esercizio: file di testo – eccezioni . . . Le eccezioni vengono catturate nel main, dove oltre a stampare l’eccezione, visualizziamo anche lo stack delle chiamate al momento della eccezione, con il metodo predefinito printStackTrace della classe Exception . . . catch(Exception ex) { System.out.println(ex.toString()); ex.printStackTrace(); System.exit(1); } http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 39 . . .Esercizio: file di testo - eccezioni . . . Lanciamo il programma senza aver creato il file email.txt Questo è ex.toString() java.io.FileNotFoundException: email.txt (No such file or directory) Questo è l’output di printStackTrace() java.io.FileNotFoundException: email.txt (No such file or directory) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init> (FileInputStream.java:106) at java.io.FileInputStream.<init> (FileInputStream.java:66) at java.io.FileReader.<init>(FileReader.java:41) at StringIO.leggiFile(StringIO.java:8) at StringIO.main(StringIO.java:46) http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 40 Esercizio: file di testo – posizione dei file Si ottiene lo stesso tipo di eccezione anche se si sposta il file in una directory diversa da quella dove si lancia il comando java, cioè dove il programma si aspetta di trovare il file E’ possibile specificare il percorso completo insieme al nome del file: Lista l = StringIO.leggiFile("/tmp/email.txt"); Attenzione: in ambiente Windows è diverso: Lista l = StringIO.leggiFile(“C:\\tmp\\email.txt"); http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 41 . . .Esercizio: file di testo ed eccezioni. . . Dopo aver creato un file email.txt -=> stampo il contenuto del file <-From: [email protected] Subject: Re: [Nutch-dev] Image Search Engine Input (General storage of extra data for use by Nutch) xyz -=> fine senza errori <-- E ci aspettiamo di trovare un file email1.txt con lo stesso contenuto di email.txt http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 42 Esercizio: file di testo (2). . . Dati due file di testo su hard drive, vogliamo confrontarne il contenuto per determinare se sono uguali oppure no Sfruttiamo la classe precedente, in particolare il metodo leggiFile per costruire due liste, una per ogni file di input Implementiamo il metodo confrontaFile per il confronto delle due liste che ritorna un booleano: true se i due file contengono lo stesso testo, false altrimenti http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 43 . . .Esercizio: file di testo (2). . . public static boolean confrontaFile (String fn1, String fn2) throws IOException{ // creo le due liste a partire dai nome dei file Lista l1 = StringIO.leggiFile(fn1); Lista l2 = StringIO.leggiFile(fn2); boolean stop = false; // continuo fino alla fine di uno dei file // oppure quando ho trovato due linee che // non corrispondono while (!l1.estVuota() && !l2.estVuota() && !stop){ String linea1 = (String)l1.car(); String linea2 = (String)l2.car(); . . . http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 44 . . .Esercizio: file di testo (2). . . // confronto le due stringhe if (linea1.equals(linea2)) { // proseguo con la linea successiva l1 = l1.cdr(); l2 = l2.cdr(); } else { stop = true; } } // se sono uscito mentre almeno una delle // due liste non è vuota, allora i due // file non sono uguali return l1.estVuota() && l2.estVuota(); } http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 45 . . .Esercizio: file di testo (2). . . public static void main(String[] args) throws IOException { try { Lista l = StringIO.leggiFile("email.txt"); System.out.println ("--> stampo il contenuto del file <--"); StringIO.stampa(l); StringIO.scriviFile(l, "email1.txt"); boolean b; b = StringIO.confrontaFile ("email.txt", "email1.txt"); System.out.println("uguali? :"+b); } . . . http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 46 . . .Esercizio: file di testo (2). . . catch(Exception ex) { System.out.println(ex.toString()); ex.printStackTrace(); System.exit(1); } System.out.println("--> fine senza errori <--"); } } http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 47 . . .Esercizio: file di testo (2) Output del programma: -=> stampo il contenuto del file <-From: [email protected] Subject: Re: [Nutch-dev] Image Search Engine Input (General storage of extra data for use by Nutch) xyz uguali? :true -=> fine senza errori <-- http://www.dia.uniroma3.it/~java/fondinf2/ Esercizi su I/O e Object 48