2017-01-07 12 views
1

我目前通過HORSTMANN(我推薦它,喜歡簡潔的風格),我讀「Java核心的不耐煩」有了解的關於在練習一個麻煩收集API。這次演習是如下:使用接口,而不是具體的數據結構在Java集合API

我鼓勵你使用接口,而不是具體的數據結構,例如, Map而不是TreeMap。不幸的是,這個建議僅僅到目前爲止。爲什麼不能 您使用Map<String, Set<Integer>>來表示目錄? (提示:你會如何初始化它?)你可以使用什麼類型?

雖然這些接口用於變量聲明,但下面的代碼編譯和工作時沒有問題。我錯過了什麼?

Map<String, Set<Integer>> toc = new HashMap<>(); 
toc.put("element1", IntStream.of(1, 2, 3).boxed().collect(Collectors.toSet())); 
toc.put("element2", IntStream.of (3, 4, 7).boxed().collect(Collectors.toSet())); 
toc.forEach((k, v) -> { 
    System.out.print(k + " "); 
    v.forEach(val -> System.out.print(val + " ")); 
    System.out.println(); 
}); 
} 
+1

使用接口類型的變量來保存引用亞型是不是新的,但它是不可能的話題。從一開始它就是Java的一個特色,所以本書的年代並不是問題。 –

+0

@ElliottFrisch我困惑過,因爲你可以。要回答在報價的問題,你會用它'新TreeMap的初始化<字符串,請設置>()'(或'新TreeMap的<>()'如果Java的7 +),創造的價值使用'新TreeSet中()'(或'new TreeSet <>()')。我想說Horstmann是錯誤的,但沒有完整的背景下他可能意味着別的東西。 – Andreas

+0

我想從書的問題是試圖讓你可以聲明一個變量是一個接口類型的地步,但你不能實例化一個接口:你必須實例實現該接口的類。 – alphaloop

回答

0

我有與該書的作者聯繫,他同意這個問題不清楚,它是引領讀者使用通配符類型。有問題的鍛鍊改爲:

假設你有Map<String, Set<Integer>>類型的方法參數,並有人撥打了HashMap<String, HashSet<Integer>>你的方法。怎麼了?您可以使用什麼參數類型?

答案是,在這種情況下,應該使用通配符類型:Map<String, ? extends Set<Integer>>

+0

那你明白爲什麼'的HashMap <字符串,HashSet的>'是行不通的?提示:[列出List的子類?爲什麼不是Java的泛型隱式多態?](// stackoverflow.com/q/2745265) – Tom

1

Map的接口是繼承它的接口和實現它的所有類的超類型。從Map所以TreeMap繼承,因爲你總是可以分配給一個變量,它是一個亞型的任何引用,這是完全可以接受的分配TreeMap參照Map變量。這就是所謂的拓寬引用轉換 https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.5 「拓寬引用轉換永遠不需要在運行時的特別行動,因此從來沒有在運行時拋出一個異常,他們只需在關於參考具有的方式一些其他類型組成。該在編譯時可以證明是正確的。「

所以,是的,你當然可以使用Map<String, Set<Integer>>來表示你的域模型的東西,但你不能直接實例化的接口;你必須實例化一個實現它的具體類型(類)。這是你做了什麼,當你宣稱 Map<String, Set<Integer>> toc = new HashMap<>();

由於這一原則的延伸,你可以很容易地編寫 AbstractMap<String, Set<Integer>> toc = new HashMap<>(); 因爲AbstractMap也是HashMap的超類型。

一般要申報,可容納最大可能集亞型的引用,在你的邏輯工作的可變最廣泛的類型。如果您需要有排序的地圖,那麼'地圖'太寬;它不強制分類。您必須將變量聲明爲TreeMap或更好,SortedMap

通常界面是最廣泛的適用類型,但是如果不是這樣,你必須考慮它。

編輯:在評論中提到光SortedMap

+1

有一個'SortedMap'界面,您可以使用,而不是'TreeMap'。 – pvorb

相關問題