2

したがって、私は hashCode のオーバーライドに精通しておらず、hashCode メソッドで何らかの形で無限再帰が行われているようです。

これが私のシナリオです。システム内の重複オブジェクトをチェックするキャッシュ オブジェクトであるクラス DuplicateCache があります。Duplicate オブジェクトを表す静的内部クラス Duplicate があります。

DuplicateCache は HashMap を保持して、そのすべてのエントリを追跡します。各エントリは、キーとしての Duplicate オブジェクトと値としての Long オブジェクトで構成されます。

Duplicate オブジェクト キーを使用してすべての操作を実行しています。HashMap に put メソッドを実行すると、Duplicate オブジェクトの hashCode() メソッドで無限再帰が発生します。

重複する hashCode() メソッドは、オーバーライドする必要があった別のクラスの hashCode を呼び出すため、後でそれを含めます。

これ以上苦労することなく、問題のある Duplicate クラスのコードを次に示します。

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

このクラスでは、値フィールドは 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() は、テーブル内の古いエントリを時間ベースで削除するメソッドです。ハッシュ テーブルは HashMap オブジェクトです。

ありがとう!

4

3 に答える 3

5

StackOverflowError場合、スタック トレースがどこで終了するかは重要ではありません (これは基本的にランダムであり、問​​題とはまったく関係がない可能性があります)。

あなたのhashCode()メソッドは問題ないように見えますが、StackOverflowError.

于 2010-01-15T19:32:18.043 に答える
0

スタックトレースを投稿します。SO例外が発生している場合は、オブジェクト定義のどこかに参照ループがあることは明らかです。スタックトレースにより、どこにあるかがすぐにわかります。

于 2010-01-15T19:25:07.480 に答える
0

ほとんどの場合、StackOverflowError は、実行パスに無限の再帰があることを意味します。

于 2010-01-16T02:13:32.997 に答える