开发者

I tried to forward a method to super, but it occasionally doesn't work. Why?

This is the code in question, simplified for this 开发者_JAVA技巧example:

/** 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);
  }
}


Oh goodness you overwritten a hashtable. Yeah the documentation isn't especially useful in this case.

I'll just cite Peter Norvig on that one, since he said it better than I could:

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

You need to be careful when passing to super that you fully understand what the super method does. In this case, the contract for Hashtable.put is that it will record a mapping between the key and the value in the table. However, if the hashtable gets too full, then Hashtable.put will allocate a larger array for the table, copy all the old objects over, and then recursively re-call table.put(key, value). Now, because Java resolves methods based on the runtime type of the target, in our example this recursive call within the code for Hashtable will go to HashtableWithPlurals.put(key, value), and the net result is that occasionally (when the size of the table overflows at just the wrong time), you will get an entry for "dogss" as well as for "dogs" and "dog". Now, does it state anywhere in the documentation for put that doing this recursive call is a possibility? No. In cases like this, it sure helps to have source code access to the JDK.

The solution? Don't extend HashTable but use a wrapper class that stores internally a HashTable and forwards the necessary methods to it (not a 100% perfect solution but it'll be good enough in most cases and doesn't have those problems). Well or look at the source code extremely well and make sure you understand exactly what's going on.. and write lots of tests (and some fuzztests)

PS: That's pretty much my favorite example when arguing with people that think OOP makes everything so much easier and completely foolproof - there's still no silver bullet ;)

PPS: Considering that both examples are pretty much the same - care to tell us where you got it? Just curious, because it seems someone took the norvig post as inspiration here ;)


Should you be returning super.get(key);?

Edit

Now that I looked more carefully, should your put method just be void? Why is it returning an Object in the first place?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜