閱讀617 返回首頁    go 阿裏雲 go 技術社區[雲棲]


為什麼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函數有關係。不過感覺不大靠譜,這個隻能說是一些另類的應用。

https://stackoverflow.com/questions/857420/what-are-the-reasons-why-map-getobject-key-is-not-fully-generic


最後更新:2017-04-02 16:47:46

  上一篇:go ubuntu vi上下左右鍵無法使用?
  下一篇:go Java 筆記10