2014-03-25 73 views
0

在Java中,我創建了一組對象(相同類型),其中每個對象都包含一個名爲name的字符串字段。集合,對象和它們的全部都是在構造函數中生成的,永遠不會被更改。我希望能夠輕鬆找到給定name的對象。使用給定名稱在不變列表中查找元素

class Program { 
    final Collection<Foo> foos; 

    Program() { 
     foos = new HashSet<>(); // Note: I'm willing to use another type of collection 
     foos.add(new Foo("First", 7)); 
     foos.add(new Foo("Qwerty", 4)); 
    } 

    get(String name) { 
     // how? 
    } 
} 

class Foo { 
    final String name; 
    int size; 

    Foo(String name, int size) { 
     this.name = name; 
     this.size = size; 
    } 
} 

我能想到的獲得富與給定name的幾種方法。我可以製作一個Map<String,Foo>,但是這似乎使用了比真正需要更多的內存(每個字符串都必須在內存中複製,並且存在全新的數據結構)。或者,我可以做一個簡單的foreach循環,但這是O(n)效率,我正在尋找O(1)或接近它。

+1

請注意,'HashSet'在幕後使用了'HashMap'。 –

+0

使用'Map'而不是'Set'。 @SotiriosDelimanolis任何'Set'都在幕後使用'Map'。 –

+0

'Set's並不是真正用於檢索。 –

回答

2

首先,正如在評論中指出的那樣,the implementation of HashSet actually uses a HashMap,所以不要指望這個設置的內存效率更高。

其次,您聲明String實例在使用映射時必須重複。這是而不是是真的。 Java的按引用傳遞非原始類型的實例,而不是價值,所以如果你創建這樣的映射:

map.put(foo.getName(), foo); 

String實例中Foo點你name領域將是完全一樣的情況下,該地圖的關鍵點將指向。你並沒有浪費任何記憶。也是the JVM will reuse string literals注意,因此,即使是這樣的:

map.put("alice", new Foo("alice")); 

不會導致內存被複制的字符串。一般來說,你應該小心做出這樣的假設,因爲不僅JVM,還有編譯器,可能會在你背後做出很多優化。關注功能和可讀性,然後在發現瓶頸時再進行優化。 *插入關於過早優化的陳詞濫調。*

最後,Collection接口沒有提供get方法,因爲它沒有任何意義。一個集合就是這個對象的集合。它不知道任何關於它們的事情,它只是「收集」它們。從任意集合中檢索對象與請求某人打開未知物品的抽屜並將其中的藍色物體取出相同。這個人必須看每件物品才能找到藍色的物品,但可能會出現多種藍色物品,因此,不僅需要線性時間才能找到藍色物品,還可能存在重複物品(不是在Set之間),如果是這樣,你可能不知道其中你得到的藍色東西。現在

,另一手Map提供某種形式的唯一標識符的每個項目爲「收集」關聯的手段(注意,Map一個Collection,雖然)。這正是您嘗試在Program課程中手動實施的內容。您需要一個Foo對象的集合,並且您想通過名稱來唯一標識它們。這是一張地圖的用途。

注意,如果你想支持重複和剛剛獲得一些Foo與給定的名字,你正在尋找一個多重映射,你可以做一個非常粗略的實施通過映射名稱名單Foo對象(注意,你必須做必要的null檢查和列表實例自己):

Map<String,List<Foo>> map = ...; 

如果你堅持使用Collection,你將不得不遍歷它檢索對象(因爲Collection接口對迭代次序沒有任何保證)。但是,一般情況下,在需要成員測試(我有這個Foo,它是否存在於我的集合中?)的情況下使用集合,以及映射您需要檢索具有唯一標識符的對象的情況。

相關問題