【问题标题】:Recursive generic definitions and Stackoverflow in JavaJava中的递归泛型定义和Stackoverflow
【发布时间】:2012-11-18 08:52:35
【问题描述】:

我正在为一些研究项目编写确定性有限自动机的实现,并且有一些弧会导致相同的状态。 我为 State 写了这门课,但是 我想知道为什么代码会产生 Stackoverflow:

 public class State extends HashMap<Character, HashSet<State>>
 {
    public static void main(String[]args)
    {
       State t=new State();
       t.addTransition('a',t);
       t.addTransition('b',t);
    }
    public void addTransition(Character symbol, State t )
    {
        if(!this.containsKey(symbol))
        {
            this.put(symbol, new HashSet<State>());
        }
        this.get(symbol).add(t);
    }
}

令人惊讶的是,如果我删除“addTransition”调用之一,则没有错误。

我的Java版本是JDK 1.6.37,操作系统是Ubuntu Linux 12.04。

*UPD:*堆栈跟踪是:

Exception in thread "main" java.lang.StackOverflowError
at java.util.HashMap$KeyIterator.<init>(HashMap.java:843)
at java.util.HashMap$KeyIterator.<init>(HashMap.java:843)
at java.util.HashMap.newKeyIterator(HashMap.java:857)
at java.util.HashMap$KeySet.iterator(HashMap.java:891)
at java.util.HashSet.iterator(HashSet.java:170)
at java.util.AbstractSet.hashCode(AbstractSet.java:122)
at java.util.HashMap$Entry.hashCode(HashMap.java:737)
at java.util.AbstractMap.hashCode(AbstractMap.java:494)
at java.util.AbstractSet.hashCode(AbstractSet.java:126)
at java.util.HashMap$Entry.hashCode(HashMap.java:737)
at java.util.AbstractMap.hashCode(AbstractMap.java:494)
at java.util.AbstractSet.hashCode(AbstractSet.java:126)
at java.util.HashMap$Entry.hashCode(HashMap.java:737)
...
at java.util.AbstractMap.hashCode(AbstractMap.java:494)
at java.util.AbstractSet.hashCode(AbstractSet.java:126)
at java.util.HashMap$Entry.hashCode(HashMap.java:737)
at java.util.AbstractMap.hashCode(AbstractMap.java:494)
at java.util.AbstractSet.hashCode(AbstractSet.java:126)
at java.util.HashMap$Entry.hashCode(HashMap.java:737)

有没有cmets?

【问题讨论】:

  • 你可以在问题中添加堆栈跟踪吗?

标签: java generics stack-overflow dfa


【解决方案1】:

运行此程序后,我认为问题如下:由于您要添加从节点到自身的转换,因此您最终会得到一个将字符映射到自身的HashMap。当您尝试添加第二个转换时,它需要将对象添加到HashSet。问题是,为了做到这一点,它需要为你的对象计算一个哈希码。由于您的对象扩展了HashMap,它使用HashMap 代码来计算您的对象的哈希码。为此,它尝试为HashMap 中的所有对象递归构造哈希码,其中包括它自己。因此它递归地尝试计算自己的哈希码,这需要它计算自己的哈希码,这需要它自己计算哈希码,等等。

我不确定最好的解决方法是什么,但我会先不让这个对象扩展HashMapIt is generally considered a bad idea to use inheritance when you mean to use composition。将HashMap 作为对象的直接字段意味着您将打破这个循环,因为Java 将使用hashCode 的默认实现,它不会尝试为对象计算深度哈希码。

希望这会有所帮助!

【讨论】:

  • 我也在调试,结果相同。确切的逻辑可以在 AbstractMap.hashCode 函数中找到。
  • 谢谢。组合的方法(当 HashMap 是一个字段时)有效。我想我需要多次阅读您的评论才能了解实际发生的情况,但这似乎很有趣:)
  • 但我认为在这种特殊情况下,组合更直观。状态本身代表了转换表的一部分,它是一个映射。有很多基于继承的实现:stackoverflow.com/questions/1870519/…,stackoverflow.com/questions/1871403/…)...不管怎样,非常感谢你的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多