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

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

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

假设HashMap<DomainObject, Boolean> mapDomainObject do是两个有趣的变量,我在调试器中得到以下结果
map.keySet();给我一个对应于do的对象(即使@whatever simili-reference都相同),两个对象上的hashcode()返回相似的值,而两个对象之间的equals()返回truemap.containsKey(do);返回falsemap.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休眠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依赖的字段必须是不可变的

    08-07 23:03