Java重写hashCode()获取StackOverflowError

时间:2010-01-15 19:19:59

标签: java override hashcode stack-overflow

所以我不太精通覆盖hashCode,我似乎有一些无限的递归以某种方式继续使用hashCode方法。

这是我的场景,我有一个类DuplicateCache,它是一个缓存对象,用于检查系统中的重复对象。我有一个静态内部类Duplicate,它表示Duplicate对象。

DuplicateCache维护一个HashMap来跟踪其所有条目。每个条目都包含一个Duplicate对象作为键,Long对象作为值。

我正在使用Duplicate对象键执行所有操作,当我将put方法运行到HashMap中时,Duplicate对象的hashCode()方法中会出现无限递归。

重复的hashCode()方法调用另一个我必须覆盖的类的hashCode,所以我会在

之后包含它

不用多说,这是我的违规复制类的代码:

public static class Duplicate{
    private String merchId;
    private String custId;
    private MagicPrice price;
    private int status;
    private boolean compareStatus;

// snip methods        

    @Override public boolean equals(Object o){
        cat.debug("In the override equals method of Duplicate"); //DELETEME

        if(o instanceof Duplicate)
            return equals((Duplicate) o);
        else
            return false;
    }

    @Override public int hashCode() {
        return merchId.hashCode() + custId.hashCode() + price.hashCode();
    }


    /*Equals method vital to the HashMap cache operations

    How the compareStatus and status fields change this:
    if both objects have true for compareStatus -> Equals will compare the statuses
    otherwise                                   -> Equals will not compare the statuses

    If we only want to do an in_progress check, we need to compare status.
    On the other hand success checks need to ignore the status.
    */
    public boolean equals(Duplicate d){        
        try{
            if(merchId.equals(d.merchId) && custId.equals(d.custId) && (price.compareTo(d.price)==0)){
                if(this.compareStatus && d.compareStatus && this.status != d.status)
                    return false;

                return true;
            }
        }catch(PriceException pe){
            //Catching from MagicPrice.compareTo object method, return false
            return false;
        }

        return false;
    }        
}

这适用于Duplicate对象,现在是MagicPrice hashCode()方法:

@Override public boolean equals(Object o){
    if(!(o instanceof MagicPrice))
        return false;

    MagicPrice p = (MagicPrice)o;

    if(this.iso4217code.equals(p.iso4217code) && this.value.equals(p.value))
        return true;

    else return false;
}

@Override public int hashCode(){
    return value.hashCode() + this.iso4217code.hashCode();
}

在此类中,value字段是BigDecimal,iso4217code是String。为了它的价值,stackTrace最终在BigDecimal hashCode()方法中死亡,但我不相信BigDecimal hashCode()方法会被破坏。

有人可以向我解释一下我对这个hashCode()重写的缺失吗?我知道必须有一些我做错了才能产生这种行为。

以下是我的日志文件中的堆栈跟踪:

java.lang.StackOverflowError
    at java.math.BigDecimal.hashCode(BigDecimal.java:2674)
    at com.moremagic.util.MagicPrice.hashCode(Unknown Source)
    at com.moremagic.core.DuplicateCache2$Duplicate.hashCode(Unknown Source)
    at java.util.HashMap.get(HashMap.java:300)
    at com.moremagic.util.ExpirableHashMap.get(Unknown Source)
    at com.moremagic.core.DuplicateCache2.put(Unknown Source)
    at com.moremagic.core.DuplicateCache2.put(Unknown Source)
    at com.moremagic.core.DuplicateCache2.put(Unknown Source)
    at com.moremagic.core.DuplicateCache2.put(Unknown Source)
    <... and it continues with the put references for a looong time ...>

该跟踪也引用了一个专有的get方法,因此对你而言:

public Object get(Object key) {
expire();
return hashtable.get(key);
}

expire()是一种基于时间删除表中旧条目的方法 hashtable是HashMap对象

谢谢!

3 个答案:

答案 0 :(得分:5)

使用StackOverflowError,堆栈跟踪结束的位置并不重要(基本上是随机的,可能与问题完全无关),但之前的重复序列是什么 - 这应该指出究竟是什么你的问题是。

您的hashCode()方法看起来很好,它们不应该导致StackOverflowError

答案 1 :(得分:0)

发布堆栈跟踪。如果你得到一个SO异常,那么你显然在某个对象定义中有一个引用循环。堆栈跟踪应该立即显示在哪里。

答案 2 :(得分:0)

在大多数情况下,StackOverflowError意味着您在执行路径中有无限递归。