Java HashMap ne pas trouver la clé, mais il devrait
J'ai un étrange problème survenant dans mon application, je vais expliquer rapidement l'architecture globale et puis mon problème en profondeur.
- Je utiliser un service pour remplir un HashMap<DomainObject,Boolean>
venant de ma base de données (JPA) qui est remis à mon avis, par l'intermédiaire d'un EJB à distance l'appel de méthode (à l'aide d'Apache Wicket). Dans cette partie, j'ai ajouter un nouveau DomainObject
à la carte retournée afin de stocker toute nouvelle valeur de mon utilisateur final.
Le problème se produit lorsque l'utilisateur cliquait sur le bouton "ajouter" dans son navigateur, j'essaie de récupérer le nouveau point dans mon plan, mais il échoue. En jouant avec le débogueur, je fais face à les choses suivantes.
En supposant HashMap<DomainObject, Boolean> map
et DomainObject do
sont les deux variables intéressantes, j'ai les résultats suivants dans le débogueur
map.keySet();
me donne un objet correspondant à do
(même le @quel que soit simili-référence est identique), hashcode()
sur les deux objets renvoie une valeur similaire et equals()
entre les deux rendements true
map.containsKey(do);
retourne false
map.get(do)
; retourne null
, bizarre, parce que ma clé semble être dans le map
.
En supposant que ma nouvellement créé élément est la première clé énumérés par keySet()
, je ne les suivants :
map.get(new ArrayList(map.keySet()).get(0))
, et elle renvoie la valeur null.
Si cela peut aider, en joignant des points d'arrêt à mon DomainObject.equals()
et DomainObject.hashcode()
méthodes, j'ai trouvé que map.get()
est seulement l'appel hashcode()
et pas equals()
.
La seule solution que j'ai trouvé est de recréer une nouvelle carte sur le dessus de l'existant new HashMap(map)
, dans cette nouvelle carte, je n'ai aucun problème à tous à la recherche d'un objet par sa clé.
J'espère que quelqu'un ici peut donner mon un pointeur sur ce qui se passe, merci.
Environnement :
- Sun Java 1.6.0_26 x64 sous OS X 10.7.1
- OpenJDK 1.6.0_18 x64 sous Debian 6.0.2 (2.6.32)
- Apache Wicket 1.4.17
- Oracle Glassfish 3.1.1
- JBoss, Hibernate 3.6.5
DomainObject
code :
public class AssetComponentDetailTemplate extends BaseEntite<Long> {
public enum DataType {
TXT,
DATE,
INT,
JOIN,
LIST,
COULEURS,
REFERENCE
}
public enum Tab {
IDENTITE,
LOCALISATION,
CYCLE_DE_VIE,
FINANCE,
RESEAU,
DETAIL
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private DataType dataType;
private Integer classNameId;
private Long orderId;
private Long nextAssetComponentDetailTemplateId;
private String unit;
@Enumerated(EnumType.STRING)
private Tab tab;
@Column(nullable = false)
private Long uniqueOrganizationId;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "idAssetComponentDetailTemplate", insertable = false, updatable = false)
private List<AssetComponentDetailJoin> assetComponentDetailJoins;
private Boolean mandatory = false;
public AssetComponentDetailTemplate() {
}
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public DataType getDataType() {
return dataType;
}
public void setDataType(final DataType dataType) {
this.dataType = dataType;
}
public Integer getClassNameId() {
return classNameId;
}
public void setClassNameId(final Integer classNameId) {
this.classNameId = classNameId;
}
public Long getUniqueOrganizationId() {
return uniqueOrganizationId;
}
public void setUniqueOrganizationId(final Long uniqueOrganizationId) {
this.uniqueOrganizationId = uniqueOrganizationId;
}
public Long getNextAssetComponentDetailTemplateId() {
return nextAssetComponentDetailTemplateId;
}
public void setNextAssetComponentDetailTemplateId(final Long nextAssetComponentDetailTemplateId) {
this.nextAssetComponentDetailTemplateId = nextAssetComponentDetailTemplateId;
}
public String getUnit() {
return unit;
}
public void setUnit(final String unit) {
this.unit = unit;
}
public Tab getTab() {
return tab;
}
public void setTab(final Tab tab) {
this.tab = tab;
}
public Long getOrder() {
return orderId;
}
public void setOrder(final Long order) {
this.orderId = order;
}
public Boolean isMandatory() {
return mandatory;
}
@Override
public String toString() {
return name;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final AssetComponentDetailTemplate that = (AssetComponentDetailTemplate) o;
if (classNameId != null ? !classNameId.equals(that.classNameId) : that.classNameId != null) {
return false;
}
if (dataType != that.dataType) {
return false;
}
if (id != null ? !id.equals(that.id) : that.id != null) {
return false;
}
if (name != null ? !name.equals(that.name) : that.name != null) {
return false;
}
if (nextAssetComponentDetailTemplateId != null ?
!nextAssetComponentDetailTemplateId.equals(that.nextAssetComponentDetailTemplateId) :
that.nextAssetComponentDetailTemplateId != null) {
return false;
}
if (orderId != null ? !orderId.equals(that.orderId) : that.orderId != null) {
return false;
}
if (tab != that.tab) {
return false;
}
if (uniqueOrganizationId != null ? !uniqueOrganizationId.equals(that.uniqueOrganizationId) :
that.uniqueOrganizationId != null) {
return false;
}
if (unit != null ? !unit.equals(that.unit) : that.unit != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (dataType != null ? dataType.hashCode() : 0);
result = 31 * result + (classNameId != null ? classNameId.hashCode() : 0);
result = 31 * result + (orderId != null ? orderId.hashCode() : 0);
result = 31 * result +
(nextAssetComponentDetailTemplateId != null ? nextAssetComponentDetailTemplateId.hashCode() : 0);
result = 31 * result + (unit != null ? unit.hashCode() : 0);
result = 31 * result + (tab != null ? tab.hashCode() : 0);
result = 31 * result + (uniqueOrganizationId != null ? uniqueOrganizationId.hashCode() : 0);
return result;
}
equals
et hashCode
.Peut-on voir quelques codes à regarder?
J'ai peur extraire le code ne sera pas très facile (il est étroitement couplée à l'application). - Je ajouter
DomainObject
code.OriginalL'auteur Cedric Gatay | 2011-09-27
Vous devez vous connecter pour publier un commentaire.
[Il se fonde essentiellement sur Jesper de réponse, mais les détails peuvent vous aider à]
Depuis recréer la carte à l'aide
new HashMap(map)
est capable de trouver l'élément de je suis penser que lahashCode()
de la DomainObject changé après l'ajouter à la Carte.Par exemple, si votre DomainObject regarde la suite
Puis
La dernière déclaration ci-dessus sera de retour
null
. Parce que ledo
objet que vous avez à l'intérieur de la carte est sous le seau de"ABC".hashCode()
; il n'y a rien dans le"DEF".hashCode()
seau.Le hashCode des Objets de la carte ne doit pas changer une fois ajouté à la carte. La meilleure façon de s'assurer que les domaines sur lequel hashCode dépend doivent être immuable.
OriginalL'auteur Miserable Variable
Est votre
DomainObject
classe immuable? A-t-elle correctement mis en œuvrehashCode
etequals
méthodes?Notez que vous aurez des ennuis si votre
DomainObject
classe n'est pas immuable et que vous modifiez l'état de l'objet alors qu'il est dans la carte de manière à modifier le résultat de l'appel d'hashCode
ouequals
.hashCode
doit être mis en œuvre de telle manière qu'il renvoie la même valeur pour les deux objets chaque fois queequals
renvoie la valeur true si la comparaison de ces objets. Voir la documentation de l'API dejava.lang.Object.hashCode()
pour obtenir des informations détaillées.OriginalL'auteur Jesper
Ici est votre indice:
Pour les objets pour être considérés comme égaux, leurs codes de hachage ne doit pas seulement être similaires, ils doivent être identiques.
Si deux objets ont différents codes de hachage, puis dans la mesure où le conteneur est concerné, les objets sont différents. Il n'y a même pas besoin de l'appeler
equals()
.De la Javadoc:
Si j'étais vous, je voudrais prendre un coup d'oeil étroit à
DomainObject.hashcode()
etDomainObject.equals()
pour voir quelle en est la cause que le contrat soit rompu.hashcode()
était mauvais, la nouvelle création de cartes à l'aide de l'ancien ne fonctionnerait pas, ai-je le droit ?OriginalL'auteur NPE
map.get(do)
retournull
pourrait facilement être expliqué par l'hypothèse que leBoolean
valeur de cette clé peut êtrenull
maismap.containsKey(do)
retourfalse
nécessiteraitdo
'shashCode
être différent au moment de l'appelcontainsKey(do)
àhashCode
au moment de la récupération de lakeySet
.Pour voir ce qui se passe, vous pouvez (temporairement) l'utilisation d'un plus détaillé de la mise en œuvre de la HashMap...
Peut-être quelque chose comme ceci:
Vous auriez besoin de la carte toutes les autres exigences de l'interface de la Carte à votre internalMap.
Remarque: Ce code n'est pas destiné à la production, ni n'est en aucune façon axés sur la performance, de nice ou de unsmelly....
2ème remarque (après avoir vu votre code): Pour utiliser votre nom de domaine-objet comme une clé pour votre table de hachage, vous ne devez utiliser l'immuable parties de votre objet pour hashCode et equals (dans ce cas, l'id de la valeur). D'autre chargement différé autres valeurs, serait de changer le hashCode...
En Réponse à votre commentaire:
imprime
Le HashCode de la clé est calculée au moment de le mettre dans la carte.
hashCode()
sur mondo
et sur la touche correspondant àdo
dans le même temps, j'obtiens exactement le même résultat, donc je dirais qu'il n'est pas un changement de l'élément dans mondo
objet (comme il fait référence au même objet). De droite les valeurs de ma carte sont soittrue
oufalse
, jamaisnull
et le débogueur affiche la valeur estfalse
dans mon cas.Voir mon dernier edit
Merci, je comprends maintenant ce qu'il se passe
OriginalL'auteur Nicktar