Java HashMap找不到密钥,但是应该 [英] Java HashMap not finding key, but it should

查看:49
本文介绍了Java HashMap找不到密钥,但是应该的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中出现一个奇怪的问题,我将快速解释全局体系结构,然后再深入探讨我的问题.

我使用服务填充来自数据库(由JPA驱动)的HashMap<DomainObject,Boolean>,该数据库又通过EJB远程方法调用(使用Apache Wicket)返回到我的视图.在这一部分中,我将新的DomainObject添加到返回的地图中,以便存储最终用户的任何新值.

当用户在其浏览器中单击添加"按钮时,会出现问题,我尝试在地图中检索新创建的项目,但失败.通过与调试器一起玩,我面临以下问题.

假设HashMap<DomainObject, Boolean> mapDomainObject do是两个有趣的变量,我在调试器中得到以下结果

map.keySet();给了我一个对应于do的对象(即使@whatever相似引用相同),两个对象上的hashcode()返回相似的值,而两个返回true equals() >

map.containsKey(do);返回false

map.get(do);返回null,很奇怪,因为我的密钥似乎在map中.

假设我新创建的项目是keySet()枚举的第一个键,我将执行以下操作: map.get(new ArrayList(map.keySet()).get(0)),它返回null.

如果有帮助,通过将断点附加到我的DomainObject.equals()DomainObject.hashcode()方法上,我发现map.get()仅在调用hashcode()而不在equals().

我发现的唯一解决方法是在现有的new HashMap(map)之上重新创建一个新地图,在此新地图中,我完全没有问题可以通过其键查找对象.

我希望这里的人能给我一个指示,谢谢.

使用的环境:

  • 在OS X 10.7.1下运行Sun Java 1.6.0_26 x64
  • Debian 6.0.2(2.6.32)下的OpenJDK 1.6.0_18 x64
  • Apache Wicket 1.4.17
  • Oracle Glassfish 3.1.1
  • JBoss Hibernate 3.6.5

DomainObject代码:

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;
}

解决方案

[这基本上是对Jesper答案的扩展,但详细信息可能会对您有所帮助]

由于使用new HashMap(map)重新创建地图能够找到该元素,因此我怀疑DomainObject的hashCode()在将其添加到地图后已更改.

例如,如果您的DomainObject看起来如下

class DomainObject {
    public String name;
    long hashCode() { return name.hashCode(); }
    boolean equals(Object other) { /* compare name in the two */'
}

然后

   Map<DomainObject, Boolean> m = new HashMap<DomainObject, Boolean>();
   DomainObject do = new DomainObject(); 
   do.name = "ABC";
   m.put(do, true); // do goes in the map with hashCode of ABC
   do.name = "DEF";
   m.get(do); 

上面的最后一条语句将返回null.因为您在地图中拥有的do对象位于"ABC".hashCode()的存储桶之下;因此, "DEF".hashCode()存储桶中什么都没有.

映射中的对象的hashCode一旦添加到映射中就不应更改.最好的方法是确保hashCode依赖的字段必须是不可变的.

I have a strange issue occuring in my application, I will quickly explain global architecture and then my problem in depth.

I use a service to populate a HashMap<DomainObject,Boolean> coming from my database (JPA driven) which is in turn returned to my view, via an EJB remote method call (using Apache Wicket). In this part, I add a new DomainObject to the map returned in order to store any new value from my end user.

The problem occurs when the user hit the "add" button in its browser, I try to retrieve the newly created item in my map, but it fails. By playing with the debugger I face the following things.

Assuming HashMap<DomainObject, Boolean> map and DomainObject do are the two variables interesting I have the following results in the debugger

map.keySet(); gives me an object corresponding to do (even the @whatever simili-reference is identical), hashcode() on both objects returns similar value and equals() between the two returns true

map.containsKey(do); returns false

map.get(do); returns null, weird because my key seems to be in the map.

Assuming my newly created item is the first key enumerated by keySet(), I do the following : map.get(new ArrayList(map.keySet()).get(0)), and it returns null.

If it can help, by attaching breakpoints to my DomainObject.equals() and DomainObject.hashcode() methods I found that map.get() is only calling hashcode() and not equals().

The only workaround I found is to recreate a new map on top of the existing one new HashMap(map), in this new map, I have no problem at all looking up an object by its key.

I hope someone here can give my a pointer on what happens, thanks.

Environment used :

  • Sun Java 1.6.0_26 x64 under OS X 10.7.1
  • OpenJDK 1.6.0_18 x64 under 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;
}

解决方案

[This basically expands on Jesper's answer but the details may help you]

Since recreating the map using new HashMap(map) is able to find the element I am suspecting that the hashCode() of the DomainObject changed after adding it to the Map.

For example if your DomainObject looks the following

class DomainObject {
    public String name;
    long hashCode() { return name.hashCode(); }
    boolean equals(Object other) { /* compare name in the two */'
}

Then

   Map<DomainObject, Boolean> m = new HashMap<DomainObject, Boolean>();
   DomainObject do = new DomainObject(); 
   do.name = "ABC";
   m.put(do, true); // do goes in the map with hashCode of ABC
   do.name = "DEF";
   m.get(do); 

The last statement above will return null. Because the do object you have inside the map is under the bucket of "ABC".hashCode(); there is nothing in the "DEF".hashCode() bucket.

The hashCode of the Objects in map should not change once added to map. The best way to ensure it is that the fields on which hashCode depends must be immutable.

这篇关于Java HashMap找不到密钥,但是应该的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆