campi mutabili per gli oggetti in un insieme di Java
-
21-08-2019 - |
Domanda
Ho ragione nel ritenere che se si dispone di un oggetto che è contenuto all'interno di un set Java <> (o come una chiave in una mappa <> è per questo), tutti i campi che vengono utilizzati per determinare l'identità o relazione (via hashCode()
, equals()
, compareTo()
etc.) non può essere modificata senza causare un comportamento non specificato per le operazioni sulla raccolta? (Edit: come accennato nel quest'altra domanda )
(In altre parole, questi campi dovrebbero essere sia immutabile, o si dovrebbero richiedere l'oggetto da rimuovere dalla raccolta, poi cambiò, poi reinserito.)
Il motivo che mi chiedo è che stavo leggendo il Hibernate annotazioni guida di riferimento e ha un esempio in cui c'è un HashSet<Toy>
ma la Toy
classe ha campi name
e serial
che sono mutevoli e sono utilizzati anche nel <=> calcolo .. . una bandiera rossa se ne andò nella mia testa e io volevo solo per assicurarsi che ho capito le implicazioni di esso.
Soluzione
Il Javadoc per Set
dice
Nota: Grande attenzione deve essere esercitata se oggetti mutabili sono utilizzati come set elementi. Il comportamento di un insieme non è specificato se il valore di un oggetto è cambiato in modo che colpisce uguale confronti mentre l'oggetto è un elemento dell'insieme. Un caso particolare di questo divieto è che non è ammissibile per un set di contenere stesso come elemento.
Questo significa semplicemente è possibile utilizzare oggetti mutabili in un set, e anche cambiarli. È solo necessario assicurarsi la modifica non influisce il modo in cui il HashSet
trova le voci. Per hashCode()
, che richiederebbe non cambiando i campi utilizzati per il calcolo <=>.
Altri suggerimenti
Questo è corretto, può causare alcuni problemi di localizzare la voce di mappa. Ufficialmente il comportamento è indefinito, quindi se si aggiunge a una hashset o come una chiave in una HashMap, non dovrebbe essere cambiarla.
Sì, che causerà che accadano cose brutte.
// Given that the Toy class has a mutable field called 'name' which is used
// in equals() and hashCode():
Set<Toy> toys = new HashSet<Toy>();
Toy toy = new Toy("Fire engine", ToyType.WHEELED_VEHICLE, Color.RED);
toys.add(toy);
System.out.println(toys.contains(toy)); // true
toy.setName("Fast truck");
System.out.println(toys.contains(toy)); // false
In un HashSet / HashMap, potrebbero mutare un oggetto contenuto per modificare i risultati di compareTo()
funzionamento - Confronto relativa non viene utilizzato per individuare gli oggetti. Ma sarebbe fatale all'interno di un TreeSet / TreeMap.
Si può anche mutare gli oggetti che si trovano all'interno di un IdentityHashMap - altro che identità di un oggetto viene utilizzato per individuare i contenuti.
Anche se si possono fare queste cose con queste qualifiche, rendono il codice più fragile. Che cosa succede se qualcuno vuole passare a un TreeSet tardi, o aggiungere quel campo mutabile alla prova hashCode / uguaglianza?