Ecco i PDF di entrambe gli esoneri:
Esonero A
Esonero B
Mentre le soluzioni degli esercizi dell’esonero sono commentate solamente nelle parti da completare o da implementare.
Dato che per entrambe gli esoneri si richiedeva una certa conoscenza della riflessione, ho ritenuto opportuno inserire i metodi “chiave” di questa metodologia di programmazione all’interno del codice. Per facilitare le cose ho sfruttato solamente la classe Field, ma sarebbe stato esattamente lo stesso tipo di codice se avessi voluto sfruttare la classe Method e il metodo invoke().
Purtroppo in aula non abbiamo potuto vedere meglio tutti questi metodi, ma con una lettura intelligente della documentazione si sarebbe potuti arrivare al mio stesso codice.
Esonero A esercizio 1:
//Si importano le classi del pacchetto REFLECT import java.lang.reflect.*; //classe del MAIN public class EsoneroA_1 { static Soggetto A, B; static boolean uguali; public static void main(String[] argv) { System.out.println("Classe Persona"); A = new Persona("Persona_1", 20); B = new Persona("Persona_1", 20); uguali = A.equals(B); System.out.println("tA == B :"+uguali); uguali = B.equals(A); System.out.println("tB == A: "+uguali); uguali = A.equals(A); System.out.println("tA == A: "+uguali); uguali = B.equals(B); System.out.println("tB == B: "+uguali); System.out.println("Classe Azienda"); A = new Azienda("Azienda_1", 15); B = new Azienda("Azienda_2", 24); uguali = A.equals(B); System.out.println("tA == B :"+uguali); uguali = B.equals(A); System.out.println("tB == A: "+uguali); uguali = A.equals(A); System.out.println("tA == A: "+uguali); uguali = B.equals(B); System.out.println("tB == B: "+uguali); } } //Classe astratta SOGGETTO abstract class Soggetto { public String nome; public Soggetto(String nome) { this.nome = nome; } public abstract boolean equals(Object o); } //Class PERSONA //in questa classe doveva essere riscritto il metodo "equals" //sfruttando i metodi e le classi della riflessione class Persona extends Soggetto { public int eta; public Persona(String nome, int eta) { super(nome); this.eta = eta; } /** * @param Object o * * Il metodo equals deve confrontare la classe corrente con un altra classe * * Ricordo che le caratteristiche di un metodo equals ottimali sono: * 1) RIFLESSIVO: Per ogni riferimento X non nullo deve restituire TRUE: * X.equals(X) := true * 2) SIMMETRICO: Per ogni riferimento X, Y, si deve avere coerenza nei risultati * X.equals(Y) := Y.equals(X) * 3) TRANSITIVO: Per ogni riferimento X, Y, Z, si deve applicare la proprietà transitiva: * X.equals(Y) := Y.equals(Z) := X.equals(Z) * 4) COERENTE: se i valori degli oggetti X e Y non cambiano durante l'esecuzione del * programma, chiamate successive al metodo equals devono restituire * i medesimi risultati */ public boolean equals(Object o) { /* * confronto il riferimento all'oggetto 'o' con il riferimento * della classe attuale. Se il confronto è verificato si restituisce TRUE * e si termina il metodo */ if (this == o) return true; /* * confronto allora il riferimento all'oggetto 'o' con il valore NULL * in caso il confronto sia positivo si termina il metodo restituendo FALSE */ if (o == null) return false; /* * In caso in cui il confronto tra le classi sia verificato passo alla creazione di * due array di Field (classi contenenti le informazioni sui CAMPI di una classe) * prendendo i valori per questi array rispettivamente dal metodo * getFields() della classe corrente */ Field[] fields = getClass().getFields(); /* * Imposto una variabile booleana per il confronto dei campi delle classi * impostandone il valore iniziale su FALSE */ boolean[] uguali = new boolean[fields.length]; /* * confronto il riferimento alla classe attuale con il riferimento della classe * dell'oggetto 'o'. */ if (getClass() == o.getClass()) { /* * L'array così generato può essere scorso mediante un ciclo for */ for (int i=0; i<fields.length; i++) { try { /* * Mediante il metodo get(Object) della classe Field * si possono prelevare i valori dei campi identificati * dalla classe passata in firma al metodo * * Quindi prima si memorizza il valore del campo relativo a questa classe * in una variabile ti tipo Object * Poi si preleva il valore del campo relativo alla classe identificata da 'o' */ Object fieldThisClass = fields[i].get(this); Object fieldObjClass = fields[i].get(o); /* * La variabile booleana 'uguali' memorizza il risultato dell'uguaglianza tra * i due oggetti */ uguali[i] = fieldThisClass.equals(fieldObjClass); } catch (Exception e) { /* * in caso le operazioni del TRY causino un eccezione, si provvede * a stampare il tipo di errore scaturito e successivamente si imposta * la variabile 'uguali' su false in modo da far risultare FALSO il confronto * tra questa classe e l'oggetto 'o' */ e.printStackTrace(); for (int j=0; j<uguali.length; j++) uguali[j] = false; } } } int count = 0; for (int i=0; i<uguali.length; i++) count += (uguali[i]) ? 0 : 1; /* * a questo punto si può ritornare il valore della variabile 'uguali' * che corrisponderà a TRUE se tutti i campi risultano essere identici * altrimenti sarà uguale a FALSE se anche uno solo dei campi ha valori differenti */ return (count == 0) ? true : false; } } //Class AZIENDA //In questa classe, come nella classe Persona doveva essere //riscritto il metodo equals sfruttando la riflessione //(il metodo equals è identico a quello dell'altra classe //quindi l'ho commentato solo li) class Azienda extends Soggetto { public int dipendenti; public Azienda(String nome, int dipendenti) { super(nome); this.dipendenti = dipendenti; } public boolean equals(Object o) { if (this == o) return true; if (o == null) return false; Field[] fields = getClass().getFields(); boolean[] uguali = new boolean[fields.length]; if (getClass() == o.getClass()) { for (int i=0; i<fields.length; i++) { try { Object fieldThisClass = fields[i].get(this); Object fieldObjClass = fields[i].get(o); uguali[i] = fieldThisClass.equals(fieldObjClass); } catch (Exception e) { e.printStackTrace(); for (int j=0; j<uguali.length; j++) uguali[j] = false; } } } int count = 0; for (int i=0; i<uguali.length; i++) count += (uguali[i]) ? 0 : 1; return (count == 0) ? true : false; } }
Esonero A esercizio 2:
import javax.swing.*; import java.util.*; import java.awt.event.*; public class EsoneroA_2 { public static void main(String[] argv) { Orologio o = new Orologio(); o.start(); JOptionPane.showMessageDialog(null, "Ora attuale: "); System.exit(0); } } /** * Classe Orologio * Implementa l'interfaccia ActionListener, quindi la classe stessa diventa ascoltatrice di eventi * Contiene i due campi privati: * 1) Timer: per la gestione del timer * 2) GregorianCalendar: per prelevare l'ora dal sistema * */ class Orologio implements ActionListener { /* * NOTA: invece di scrivere Timer ho scritto * javax.swing.Timer * perché altrimenti sarebbe stato ambiguo per il compilatore * il tipo di Timer da prelevare dalle API visto che sia * il package java.util, sia il package javax.swing * hanno al loro interno una classe Timer */ private javax.swing.Timer t = null; private GregorianCalendar g = null; /* * COSTRUTTORE * istanzio il timer dicendogli di avere un tempo in ritardo generato * dal metodo generaIntervallo, e di ascoltare la classe stessa * per la generazione degli eventi */ public Orologio() { t = new javax.swing.Timer(generaIntervallo(), this); } /* * Metodo per l'esecuzione del timer (t è private) */ public void start() { t.start(); } /* * Il metodo genera un numero casuale tra 1000 e 3000 */ private int generaIntervallo() { return (int)(Math.random()*2000 + 1000); } /* * il metodo actionPerformed istanzia in 'g' un nuovo GregorianCalendar * per prendere l'ora di sistema al momento dell'istanziazione * Successivamente stampa l'ora, i minuti e i secondi sfruttando i campi statici * HOUR, MINUTE e SECOND della classe Calendar (che viene estesa da GregorianCalendar) * ultimo passo è quello di assegnare al timer un nuovo tempo di delay sfruttando * ancora una volta il metodo generaIntervallo() */ public void actionPerformed(ActionEvent e) { g = new GregorianCalendar(); System.out.println(g.get(g.HOUR) + ":" + g.get(g.MINUTE) + ":" + g.get(g.SECOND)); t.setDelay(generaIntervallo()); } }
—–
Esonero B esercizio 1:
import java.lang.reflect.*; import java.util.*; /** * In questa classe mi rappresento, nel main, un'istanza della classe Agenda * che un'istanza della classe AgendaConAllarme */ public class EsoneroB_1 { public static void main(String[] argv) { String s = AnalizzaOggetti.toString(new Agenda(new Date(), "nota")); System.out.println(s); s = AnalizzaOggetti.toString(new AgendaConAllarme(new Date(), "nota", new Date())); System.out.println(s); } } class Agenda { public Date data; public String note; public Agenda(Date data, String note) { this.data = data; this.note = note; } } class AgendaConAllarme extends Agenda { public Date dataallarme; public AgendaConAllarme(Date data, String note, Date dataallarme) { super(data, note); this.dataallarme = dataallarme; } } /** * Classe AnalizzaOggetti * con il metodo statico toString(Object o) * La classe serve da struttura per analizzare qualunque oggetto passato al metodo toString */ class AnalizzaOggetti { /* * Il metodo prende un oggetto di tipo Object in input e sfruttando i metodi della riflessione * ne analizza i campi e ne restituisce il corrispettivo valore sottoforma di stringa */ public static String toString(Object o) { /* * Inizializzo la variabile 'str' di tipo String per potervi interire * tutte le informazioni dall'analizi dell'oggetto 'o' passato al metodo */ String str; /* * Inserisco in 'str' sia il nome della classe sfruttando il metodo getClass().getName() * ## * equivalente a: * Class cl = o.getClass(); * String nomeclasse = cl.getName(); * ## * sia l'inizio della rappresentazione dei campi */ str = "Classe: "+o.getClass().getName()+"nCampi: "; /* * Nell'array di Field memorizzo i campi provenienti dalla classe di appartenenza * dell'oggetto 'o' */ Field[] fields = o.getClass().getFields(); /* * Con un ciclo for mi scorro l'array appena creato */ for (int i=0; i<fields.length; i++) { try { /* * Aggiungo a 'str' la rappresentazione sottoforma di stringa * sia del nome del campo attuale, sia del suo valore */ str += "nt"+fields[i].getName()+": "+fields[i].get(o); } catch (Exception e) {} } /* * Effettuata la rappresentazione della classe nella stringa 'str' * posso passare questa stringa come valore di ritorno del metodo */ return str; } }
Esonero B esercizio 2:
..coming soon
