Test per l'uguaglianza degli oggetti confrontando le rappresentazioni toString () degli oggetti

4

Seguendo da questa domanda - come spieghi a qualcuno che questo è solo pazzesco!:

boolean someMethod(Map<String, Object> context) {
    Object object = context.get("someProperty") 
    Object another = context.get("anotherProperty") 

    return object.toString().equals(another.toString());
}

Apparentemente il motivo per cui Object.equals(...) non è usato è che "ciò che è contenuto nella mappa non è conosciuto concretamente, ma è sicuramente noto per essere uno dei wrapper primitivi cioè String , Double , Boolean , ecc ... e che Boolean.TRUE deve essere equal(...) a String "TRUE" ".

    
posta auser 17.05.2012 - 11:38
fonte

4 risposte

7

È sbagliato perché non c'è un contratto (nemmeno un'aspettativa informale!) per toString() che garantisce che qualsiasi sottoclasse di Object la definirà in un modo compatibile con una relazione di equivalenza (leggi javadoc per Object.equals() per vedere cosa intendo).

Potrebbe funzionare per una classe in cui sai che toString() è compatibile con equals , ma questo non è il caso per i valori in Map<String, Object> !

Per un esempio ovvio dove quasi certamente il metodo non fa quello che ti aspetteresti, immagina una sottoclasse di Object che non sovrascriva toString() . In tal caso, la rappresentazione String della tua istanza è una funzione del nome della classe e dell'hashCode dell'oggetto. Quasi sicuramente non che cosa vuoi usare per testare l'uguaglianza.

    
risposta data 17.05.2012 - 14:25
fonte
7

È semplicemente folle, perché può andare storto, perché le rappresentazioni di stringhe non sono canoniche :

Double zeroDouble = new Double(0);
Integer zeroInteger = new Integer(0);
zeroDouble.doubleValue() == zeroInteger.doubleValue(); // true
zeroDouble.toString().equals(zeroInteger.toString());  // false ("0.0" vs "0")

File file1 = new File("file.txt");
File file2 = new File("FILE.TXT");
file1.equals(file2);            // true in windows, false in unix
file1.toString().equals(file2); // false ("file.txt" vs. "FILE.TXT")
    
risposta data 17.05.2012 - 11:51
fonte
0

Il metodo indicato sarebbe molto strano come parte di un'API pubblica. Che sia pazzo o meno come una parte privata o protetta di una classe dipenderebbe dal modo in cui è stata utilizzata. Il metodo sembra incapsulare due diversi aspetti bizzarri, uno dei quali potrebbe plausibilmente essere giustificabile in alcuni contesti ma non in altri; anche se sembrerebbe improbabile che entrambi siano giustificabili, non c'è una ragione particolare per cui non potrebbero esserlo.

Il primo aspetto bizzarro è il fatto che il metodo sta cercando particolari stringhe fisse all'interno delle mappe. Tale comportamento è generalmente brutto (e sarebbe probabilmente meglio se le stringhe fossero definite come costanti) ma potrebbe essere giustificabile se:

  1. La mappa non viene mai esposta al codice al di fuori del pacchetto.
  2. È necessario utilizzare alcuni tipi di raccolta per archiviare gli aggregati, ognuno dei quali consiste in una mappatura più alcuni altri bit di informazioni).
  3. L'uso della mappatura incapsulata è tale che nessuna chiave potrebbe essere in conflitto con le stringhe utilizzate per "pochi altri bit di informazioni".
  4. La mappatura è usata molto più degli altri bit di informazione archiviati nell'avvocato che usando una classe che conteneva un Map insieme agli altri bit di informazione sarebbe molto più macchinosa dell'uso di una mappa che ha pochi bit di informazione associati ai tasti magici.

Alcune lingue e framework fornirebbero mezzi alternativi per allegare informazioni supplementari a un tipo, ma l'approccio qui indicato è a volte il più pratico dato il sistema di tipi di Java.

Il secondo aspetto brutto è che il codice confronta due valori di ToString di oggetti come mezzo per confrontare gli oggetti. Nella maggior parte dei casi, gli oggetti saranno stringhe (nel qual caso si potrebbero semplicemente confrontare), oppure sarebbero di un altro tipo che ha qualche attributo di tipo String come un nome, nel qual caso si dovrebbero lanciare gli oggetti a quell'altro tipo, chiama GetName su entrambe le istanze e confronta le stringhe risultanti. Se, tuttavia, la maggior parte delle voci della tabella deve solo memorizzare le stringhe, ma alcune potrebbero aver bisogno di una voce che combini una stringa con una piccola quantità di informazioni supplementari, in alcuni casi potrebbe essere più facile memorizzare le cose nella tabella come tipo Object con l'aspettativa che ogni voce sia o String , o sia un tipo noto di oggetto. Dal momento che il sistema di tipi di Java non ha il concetto di "cosa che sarà di tipo 1 o 2", usare Object , anche se brutto, potrebbe essere l'unica alternativa pratica nei casi in cui uno dei tipi è qualcosa come String che non condividerebbe antenato comune - diverso da Object - con qualsiasi classe utente.

    
risposta data 24.10.2014 - 19:50
fonte
-6

Se sei strongmente interessato a conoscere l'uguaglianza degli oggetti, usa il metodo di oggetto di classe.

int hashCode () fornisce il valore intero chiamato hashCode che si riferisce a un oggetto.

definitely the hashcode differs object to object.
     it's a easiest way to identify object equality.
    
risposta data 17.05.2012 - 17:36
fonte

Leggi altre domande sui tag