Classe Object Java
Salve, vorrei essere sicuro di aver capito bene il procedimento
.
Firma dei metodi della classe Object:
public String toString()
public boolean equals (Object anObject)
public Object clone()
I metodi possono essere usati sia con l'ereditarietà e sia senza di essa.
In ogni caso, per il metodo clone() bisogna implementare l'interfaccia Cloneable e controllare il lancio dell'eccezione CloneNotSupportedException() con il blocco try-catch.
Vi chiedo di scrivermi il codice per tutti e 3 i metodi, ma in particolare mi serve sapere con precisione il codice dei metodi equals e clone con l'ereditarietà
.

Firma dei metodi della classe Object:
public String toString()
public boolean equals (Object anObject)
public Object clone()
I metodi possono essere usati sia con l'ereditarietà e sia senza di essa.
In ogni caso, per il metodo clone() bisogna implementare l'interfaccia Cloneable e controllare il lancio dell'eccezione CloneNotSupportedException() con il blocco try-catch.
Vi chiedo di scrivermi il codice per tutti e 3 i metodi, ma in particolare mi serve sapere con precisione il codice dei metodi equals e clone con l'ereditarietà

Risposte
L'implementazione dipende ovviamente dalla classe e da quali sono i tuoi obiettivi. Nota che se implementi equals, dovresti anche implementare hashCode. Ti consiglio di dare un occhiata ad esempio a questa pagina (segui anche il link in fondo su hashCode): http://www.javapractices.com/topic/TopicAction.do?Id=17
Leggi inoltre i seguenti articoli che riguardano clone:
http://www.javapractices.com/topic/TopicAction.do?Id=71
http://www.javapractices.com/topic/TopicAction.do?Id=69
Leggi inoltre i seguenti articoli che riguardano clone:
http://www.javapractices.com/topic/TopicAction.do?Id=71
http://www.javapractices.com/topic/TopicAction.do?Id=69
Ti ringrazio apatriarca
ma l'inglese non lo mastico abbastanza bene.
Mi potresti dire tu in linea generale come sovrascrivere il metodo equals() e il metodo clone()?
Quello che devo fare, è un confronto delle variabili di istanza tra due oggetti con il metodo equals (tipo due oggetti studenti "nome, cognome, matricola").
Mentre per clone devo clonare in maniera profonda un oggetto (oggetto studente: nome, cognome, matricola)
Questo devo farlo ANCHE con l'ereditarietà
.
Dalle slide della prof, dice che bisogna usare l'interfaccia cloneable per il metodo clone, ma dell'hash code non ne parla O.O (però l'ho letto un po')

Mi potresti dire tu in linea generale come sovrascrivere il metodo equals() e il metodo clone()?
Quello che devo fare, è un confronto delle variabili di istanza tra due oggetti con il metodo equals (tipo due oggetti studenti "nome, cognome, matricola").
Mentre per clone devo clonare in maniera profonda un oggetto (oggetto studente: nome, cognome, matricola)

Questo devo farlo ANCHE con l'ereditarietà

Dalle slide della prof, dice che bisogna usare l'interfaccia cloneable per il metodo clone, ma dell'hash code non ne parla O.O (però l'ho letto un po')
In generale il metodo equals deve confrontare lo stato di due istanze dello stesso oggetto e restituire true se devono essere considerate uguali. Il significato vero e proprio di questa affermazione dipende dalla classe e non è più di tanto generalizzabile. Idealmente la relazione data dal metodo dovrebbe essere:
1. Riflessiva. Deve cioè valere a.equals(a) == true.
2. Simmetrica. Deve cioè valere a.equals(b) == b.equals(a).
3. Transitiva. Se valgono a.equals(b) == true e b.equals(c) == true deve valere anche a.equals(c).
In altre parole deve essere una relazione di equivalenza. Deve inoltre essere
4. Consistente. a.equals(b) deve sempre restituire lo stesso valore se a e b sono non nulli e se il loro stato non cambia. In particolare il metodo non deve modificare lo stesso delle due classi.
5. Deve valere a.equals(null) == false per ogni a.
Normalmente viene implementato usando equals (o ==) per ogni campo che determina lo stato della classe. Nel tuo caso, supponendo che tutti e 3 i campi siano di tipo String e che le maiuscole non contino per il nome e il cognome mentre sono importanti per la matricola si avrebbe qualcosa come il seguente:
Siccome però la matricola è già normalmente considerata un identificativo per lo studente, si potrebbe supporre di usare quello come unico campo importante per stabilire l'uguaglianza tra le due classi e implementare equals nel modo seguente:
E' infine generalmente necessario implementare anche hashCode. Questo metodo è usato in classi come HashMap e per il corretto funzionamento di queste classi insieme alla tua classe è necessario che hashCode restituisca lo stesso valore per istanze valutate come uguali da equals. Per la classe studente si potrebbe implementare hashCode nel modo seguente (non è certamente l'unico ed è basato sul primo metodo di confronto):
In linea di massima il metodo equals NON funziona con l'ereditarietà. Supponi di aver infatti implementato una seconda classe StudenteConData che erediti da Studente e con un campo aggiuntivo per la data di nascita per esempio. Supponendo di voler considerare anche questo dato per lo stato, come implementeresti il metodo equals per questa nuova classe figlia? Supponiamo di avere un'istanza s1 di tipo Studente e un'instanza s2 di tipo StudenteConData. Supponiamo che le due classi siano identiche tranne per la data. Quale dovrebbe essere il valore di
e quale quello di
? Questo piccolo esempio ti dovrebbe mostrare le difficoltà nell'uso di equals con l'ereditarietà. E' in questi casi preferibile la composizione.
1. Riflessiva. Deve cioè valere a.equals(a) == true.
2. Simmetrica. Deve cioè valere a.equals(b) == b.equals(a).
3. Transitiva. Se valgono a.equals(b) == true e b.equals(c) == true deve valere anche a.equals(c).
In altre parole deve essere una relazione di equivalenza. Deve inoltre essere
4. Consistente. a.equals(b) deve sempre restituire lo stesso valore se a e b sono non nulli e se il loro stato non cambia. In particolare il metodo non deve modificare lo stesso delle due classi.
5. Deve valere a.equals(null) == false per ogni a.
Normalmente viene implementato usando equals (o ==) per ogni campo che determina lo stato della classe. Nel tuo caso, supponendo che tutti e 3 i campi siano di tipo String e che le maiuscole non contino per il nome e il cognome mentre sono importanti per la matricola si avrebbe qualcosa come il seguente:
public class Studente { private final String nome; private final String cognome; private final String matricola; public Studente(String nome, String cognome, String matricola) { this.nome = nome; this.cognome = cognome; this.matricola = matricola; } public final String nome() { return nome; } public final String cognome() { return cognome; } public final String matricola() { return matricola; } @Override public boolean equals(Object obj) { if (this == obj) return true; // test veloce per la proprietà riflessiva if (obj == null) return false; // test veloce per l'ultima proprietà if (!(obj instanceof Studente)) return false; // non è uno studente.. Studente s = (Studente) obj; return this.matricola.equals(s.matricola) && this.cognome.equalsIgnoreCase(s.cognome) && this.nome.equalsIgnoreCase(s.nome); } }
Siccome però la matricola è già normalmente considerata un identificativo per lo studente, si potrebbe supporre di usare quello come unico campo importante per stabilire l'uguaglianza tra le due classi e implementare equals nel modo seguente:
@Override public boolean equals(Object obj) { if (this == obj) return true; // test veloce per la proprietà riflessiva if (obj == null) return false; // test veloce per l'ultima proprietà if (!(obj instanceof Studente)) return false; // non è uno studente.. Studente s = (Studente) obj; return this.matricola.equals(s.matricola); }
E' infine generalmente necessario implementare anche hashCode. Questo metodo è usato in classi come HashMap e per il corretto funzionamento di queste classi insieme alla tua classe è necessario che hashCode restituisca lo stesso valore per istanze valutate come uguali da equals. Per la classe studente si potrebbe implementare hashCode nel modo seguente (non è certamente l'unico ed è basato sul primo metodo di confronto):
@Override public int hashCode() { return this.matricola.hashCode() ^ this.cognome.toLowerCase().hashCode() ^ this.nome.toLowerCase().hashCode(); }
In linea di massima il metodo equals NON funziona con l'ereditarietà. Supponi di aver infatti implementato una seconda classe StudenteConData che erediti da Studente e con un campo aggiuntivo per la data di nascita per esempio. Supponendo di voler considerare anche questo dato per lo stato, come implementeresti il metodo equals per questa nuova classe figlia? Supponiamo di avere un'istanza s1 di tipo Studente e un'instanza s2 di tipo StudenteConData. Supponiamo che le due classi siano identiche tranne per la data. Quale dovrebbe essere il valore di
s1.equals(s2)
e quale quello di
s2.equals(s1)
? Questo piccolo esempio ti dovrebbe mostrare le difficoltà nell'uso di equals con l'ereditarietà. E' in questi casi preferibile la composizione.
In breve, il metodo copy è da evitare ad ogni costo. Il principale motivo è che è molto difficile implementarlo in modo corretto ed esistono alternative spesso più semplici. Nel primo link che ti avevo mandato c'è un'implementazione del metodo clone. Come c'è scritto nel commento al metodo, per implementare clone si deve:
1. Implementare cloneable
2. Implementare il metodo clone pubblico in modo che lanci l'eccezione CloneNotSupportedException (è importante per le classi figlie che non siano interessate a "farsi clonare".
3. All'interno del metodo richiamare super.clone() e fare il casting verso il tipo della classe (questo metodo si occupa dei campi immutabili senza problemi).
4. Fare una copia esplicita dei campi non immutabili.
5. Tutte le classi figlie devono implementare il metodo clone per non incontrare problemi.
Ti riporto il link con l'implementazione di clone Java Practices -> Avoid clone.
Il metodo più semplice e consigliato è quello di implementare semplicemente il costruttore di copia e usare quello. Se hai bisogno di un esempio chiedi pure.
1. Implementare cloneable
2. Implementare il metodo clone pubblico in modo che lanci l'eccezione CloneNotSupportedException (è importante per le classi figlie che non siano interessate a "farsi clonare".
3. All'interno del metodo richiamare super.clone() e fare il casting verso il tipo della classe (questo metodo si occupa dei campi immutabili senza problemi).
4. Fare una copia esplicita dei campi non immutabili.
5. Tutte le classi figlie devono implementare il metodo clone per non incontrare problemi.
Ti riporto il link con l'implementazione di clone Java Practices -> Avoid clone.
Il metodo più semplice e consigliato è quello di implementare semplicemente il costruttore di copia e usare quello. Se hai bisogno di un esempio chiedi pure.
Ho capito tutto, grazie
.
Cmq sì, mi servirebbe un esempio per clone() e pure con clone() e l'ereditarietà
.

Cmq sì, mi servirebbe un esempio per clone() e pure con clone() e l'ereditarietà

Nel link che ho riportato è riportata un'implementazione del metodo clone..
Ho visto ma non ho capito bene come funziona, sopratutto per l'ereditarietà.
Cmq per il metodo equals() funziona perfettamente
, tranne che per l'ereditarietà, c'è un errore in una riga di codice ma nn ho capito perché...???
sovrascrittura di equals senza ereditarietà
sovrascrittura equals, con ereditarietà
Cmq per il metodo equals() funziona perfettamente

sovrascrittura di equals senza ereditarietà
public class Base { public Base(String n, String c) { this.nome = n; this.cognome = c; } String nome; String cognome; @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null) { return false; } if(!(obj instanceof Base)) { return false; } Base b = (Base)obj; return this.nome.equals(b.nome) && this.cognome.equalsIgnoreCase(b.cognome); } @Override public String toString() { return nome+cognome; } public static void main(String[] args) { Base ba = new Base("pippo","baudo"); Base bb = new Base("pippo","baudo"); Base bc = new Base("roger","nave"); Basedue d = new Basedue("pippo","baudo"); Basedue dc = new Basedue("roger","nave"); System.out.println(ba.equals(bb));//true System.out.println(ba.equals(bc));//false System.out.println(ba.equals(d));//false System.out.println(ba.equals(dc));//false } } //questa è un'altra classe - Basedue public class Basedue { public Basedue(String n, String c) { nome = n; cognome = c; } String nome; String cognome; public static void main(String[] args) { } }
sovrascrittura equals, con ereditarietà
public class Base extends Basedue { public Base(String n,String c) { super(n,c); } public Base( ) { nome = "pietro"; cognome = "nardi"; } String nome; String cognome; @Override public boolean equals(Object obj) { if(obj == null) { return false; } if(!(obj instanceof Basedue)) { return false; } Basedue b = (Basedue) obj; return nome.equals(b.nome) && cognome.equalsIgnoreCase(b.cognome); //da errore } public static void main(String[] args) { Base b = new Base("pietro","nardi"); Basedue c = new Basedue("pietro","nardi"); System.out.println(b.equals(c)); // da errore } } public class Basedue { public Basedue(String n, String c) { nome = n; cognome = c; } public Basedue() { } String nome; String cognome; }
In che senso da errore? Quale?