為什麼Java中的HashMap<K, V>的get函數是get(Object key),而不是get(K key)?
幫別人的代碼改bug,發現有一大堆bug是由get或者remove傳遞進去的參數類型不匹配而造成的。
比如:
Map<Short, String> m = new HashMap(); m.put(new Short((short) 2), "2222"); System.out.println(m.get(2));
上麵的代碼輸出是null。
一般人很難發現傳遞進去的int和Short類型不匹配,而且IDE,編譯器也沒有提示。當然通過一些分析工具可以檢查出來。
真的感到很困惑,Java中的容器的一些函數,參數都是Object類型,如HashMap中的get,remove函數,Set中的contains函數。
為什麼不明確它們的類型?這樣編譯器可以檢查出類型不匹配的錯誤。
Google之,google的一個工程師給出了答案:https://smallwig.blogspot.com/2007/12/why-does-setcontains-take-object-not-e.html
為了簡單起見,以Set容器為例:
定義一個簡單的S,隻有一個簡單的contains函數:
class S<K>{ public void contains(K k){ System.out.println("S<K>,contains(K k)"); } }
假如我們有個函數,想要處理Foo類的集合:
public void doSomeReading(S<Foo> foos) { }要是我們想能同時處理Foo類的子類(如SubFoo)的集合,那應該這樣定義:
public void doSomeReading(S<? extends Foo> foos) { }
一切看起來很好,但是如果我們把代碼都合起來,就會發現悲劇了:
class S<K>{ public void contains(K k){ System.out.println("S<K>,contains(K k)"); } } class Foo{ } class SubFoo extends Foo{ } public void doSomeReading(S<? extends Foo> foos) { Foo f = new Foo(); SubFoo subFoo = new SubFoo(); foos.contains(f); //這裏eclipse會提示出錯,這裏隻有填null時才不會報錯 foos.contains(subFoo); //同樣錯誤 foos.contains(null); }
這時編譯器不幹了,它表示不能工作了。
原來在S<K>類的定義中,我們明確contains(K k)函數隻能接受一個明確類型的參數。
但是在doSomeReading函數中,編譯器無法確定到底是什麼類型,它是Foo類型,還是SubFoo類型,還是SubSubFoo類型?
編譯器無從得知,所以它隻允許null類型的參數。
===========================================================
對於這個解析,話說還是有點鬱悶。
也有另外的解析,認為和equals函數有關係。不過感覺不大靠譜,這個隻能說是一些另類的應用。
最後更新:2017-04-02 16:47:46