Переопределение Java hashCode () получает StackOverflowError - PullRequest
2 голосов
/ 15 января 2010

так что я не очень разбираюсь в переопределении hashCode, и у меня, похоже, есть какая-то бесконечная рекурсия, как-то происходящая с методом hashCode.

Вот мой сценарий, у меня есть класс DuplicateCache, который является объектом кеша, который проверяет дубликаты объектов в нашей системе. У меня есть статический внутренний класс Duplicate, который представляет объекты Duplicate.

DuplicateCache поддерживает HashMap для отслеживания всех своих записей. Каждая запись состоит из объекта Duplicate в качестве ключа и объекта Long в качестве значения.

Я выполняю все свои операции, используя ключи объекта Duplicate, и когда я запускаю метод put в HashMap, в методе hashCode () объекта Duplicate возникает бесконечная рекурсия.

Метод 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, а код iso4217 - это строка. В конце концов, stackTrace, наконец, умирает в методе BigDecimal hashCode (), но я не думаю, что метод hashCode () BigDecimal будет сломан.

Может кто-нибудь объяснить мне, что мне не хватает в этом переопределении 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 ]

5 голосов
/ 15 января 2010

При StackOverflowError не важно, где заканчивается трассировка стека (это в основном случайное и может быть совершенно не связано с проблемой), но какова повторяющаяся последовательность до этого - и это должно точно указывать, в чем ваша проблема есть.

Ваши hashCode() методы выглядят хорошо, они не должны вызывать StackOverflowError.

0 голосов
/ 16 января 2010

В большинстве случаев StackOverflowError означает, что у вас есть бесконечная рекурсия в вашем пути выполнения.

0 голосов
/ 15 января 2010

Опубликовать трассировку стека. Если вы получаете SO Exception, то вы, очевидно, имеете где-то ссылочный цикл в определениях объектов. Трассировка стека должна сразу показывать, где.

...