这是有问题的代码,为此示例简化:
/** A version of Hashtable that lets you do
* table.put("dog", "canine");, and then have
* table.get("dogs") return "canine". **/
public class HashtableWithPlurals extends Hashtable {
/** Make the table map both key and key + "s" to value. **/
public Object put(Object key, Object value) {
super.put(key + "s", value);
return super.put(key, value);
}
}
Run Code Online (Sandbox Code Playgroud)
哦,天哪,你覆盖了哈希表.是的,在这种情况下,文档并不是特别有用.
我会引用Peter Norvig的话,因为他说的比我更好:
public class HashtableWithPlurals extends Hashtable {
/** Make the table map both key and key + "s" to value. **/
public Object put(Object key, Object value) {
super.put(key + "s", value);
return super.put(key, value);
}
}
Run Code Online (Sandbox Code Playgroud)
在传递给super时你需要小心,你完全理解超级方法的作用.在这种情况下,Hashtable.put的合同是它将记录键和表中的值之间的映射.但是,如果散列表太满,那么Hashtable.put将为表分配一个更大的数组,复制所有旧对象,然后递归地重新调用table.put(key,value).现在,因为Java根据目标的运行时类型解析方法,在我们的示例中,Hashtable的代码中的这个递归调用将转到HashtableWithPlurals.put(key,value),并且最终的结果是偶尔(当大小时)桌子在错误的时间溢出),你会得到一个"dogss"以及"dog"和"dog"的条目.现在,它是否在文档中的任何位置说明了进行此递归调用是否可能?在这种情况下,确保有源代码访问JDK是有帮助的.
解决方案?不要扩展HashTable,而是使用一个内部存储HashTable的包装类,并将必要的方法转发给它(不是100%完美的解决方案,但在大多数情况下它都足够好并且没有这些问题).好吧或者看看源代码非常好,并确保你完全理解发生了什么...并写了很多测试(和一些fuzztests)
PS:这是我最喜欢的例子,当与人们争论时,认为OOP使一切变得如此简单和完全万无一失 - 仍然没有银弹;)
PPS:考虑到两个例子几乎相同 - 请告诉我们你在哪里得到它?只是好奇,因为似乎有人把norvig帖子作为灵感来到这里;)