Java 重写 hashCode() 得到 StackOverflowError
所以我不太熟悉重写 hashCode 并且我似乎在 hashCode 方法中以某种方式进行了一些无限递归。
这是我的场景,我有一个 DuplicateCache 类,它是一个缓存对象,用于检查系统中的重复对象。我有一个静态内部类 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() 是一种基于时间删除表中旧条目的方法 hashtable 是 HashMap 对象
谢谢!
so I'm not well versed in overriding hashCode and I seem to have some infinite recursion somehow going on with the hashCode method.
Here is my scenario, I have a class DuplicateCache that is a cache object that checks for duplicate objects in our system. I have a static inner class Duplicate which represents the Duplicate objects.
The DuplicateCache maintains a HashMap to keep track of all its entries. Each entry consists of a Duplicate object as the key and a Long object as the value.
I am performing all my operations using the Duplicate object keys, and when I run the put method into the HashMap, there becomes infinite recursion in the hashCode() method of the Duplicate object.
The hashCode() method in duplicate calls a hashCode of another class I had to override, so I'll include that after
Without further ado, here is my code for the offending Duplicate class:
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;
}
}
That does it for the Duplicate object, now the MagicPrice hashCode() method:
@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();
}
In this class the value field is a BigDecimal and the iso4217code is a String. For what its worth the stackTrace finally dies in the BigDecimal hashCode() method, but I wouldn't believe the BigDecimal hashCode() method would be broken.
Could someone please explain to me what I am missing about this hashCode() overriding? I know there must be something I'm doing wrong to generate this behaviour.
Here is the stack trace from my log file:
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 ...>
Also that trace references a proprietary get method so heres that for you:
public Object get(Object key) {
expire();
return hashtable.get(key);
}
expire() is a method that does time based removal of old entries in the table
hashtable is the HashMap object
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于 StackOverflowError,堆栈跟踪结束的位置并不重要(这基本上是随机的,并且可能与问题完全无关),重要的是之前的重复序列是什么 - 并且应该准确指出什么你的问题是。
您的
hashCode()
方法看起来不错,它们不应该导致StackOverflowError
。With a
StackOverflowError
, it's not important where the stack trace ends (that's basically random, and may be completely unrelated to the problem), but what the repeating sequence before that is - and that should point out exactly what your problem is.Your
hashCode()
methods look fine, they shouldn't be able to cause aStackOverflowError
.发布堆栈跟踪。如果您收到 SO 异常,那么您显然在对象定义中的某处出现了引用循环。堆栈跟踪应使其立即显而易见。
Post the stack trace. If you're getting a SO Exception then you've obviously got a referential loop in the object definitions somewhere. The stack trace should make it immediately apparent where.
在大多数情况下,StackOverflowError 意味着您的执行路径中有无限的递归。
In most cases StackOverflowError means that you have endless recursion in your execution path.