2015-02-12 78 views
1

假設我有理由要求通過多個值類型快速查找類實例,爲了解釋這一點,我將以遊戲服務器爲例。Java - 高效的集合管理

可以說服務器處理帶有靜態識別號碼的用戶。此號碼用於與特定玩家進行交流和互動(即:私人聊天,交易請求,戰鬥,公會邀請等)。

這就需要通過自己的身份證號碼,根據我目前的經驗,要做到這一點的最好辦法看玩家了常見的用法是,像這樣:(請糾正我,如果我錯了。)

HashMap<Integer, Player> 

然而,在處理網絡問題時,有很多時候我還需要讓播放器與網絡會話相關聯,或者像有些人可能更熟悉的「套接字」那樣。這會看起來像這樣:

HashMap<Connection, Player> 

那麼我想就是弄清楚,我應該走這條路:

HashMap<Integer, Player> playersById; 
HashMap<Connection, Player> playersByConnection; 

或者我應該做的事情多一點「一起搗爛」像這樣:

HashMap<Object[], Player> playersOnline; 

和具有Object[0]爲整數,並且Object[1]作爲Connection,然後使用查找過程中所需的一個。

或者這兩種方法都是有效的和不正確的,有沒有更好/更快的方式來查看它們的整數或連接而不重複集合?

任何洞察力將非常感激。

編輯:此外,有沒有什麼反對HashSet<>HashMap<>包含相同的類引用?我注意到HashSet<>在迭代上比HashMap<>效率高得多,並且一直保持用於查找的Map和用於迭代的Set,這是不好的做法嗎?

+0

@aliteralmind - 感謝您的鏈接,儘管已經閱讀了所有內容! – Hobbyist 2015-02-12 04:23:44

+0

您是否量化了迭代HashSet和HashMap之間的性能差異?你在HashSet中保留了什麼? 「玩家」對象? – 2015-02-12 04:25:24

+1

@aliteralmind標記爲重複?真?這個問題是關於在地圖上是否有多域密鑰是一個好主意:關於選擇實現只有一小部分附錄。 '重複'是關於一個簡單的方法來選擇使用哪個集合:只與這個問題隱約相關。 – sprinter 2015-02-12 05:02:17

回答

-1

首先,我必須提一下無價的What Collection should I use流程圖。


絕對使用兩個HashMap中/非「砸」版本爲兩個獨立的地圖,然後將它抽象掉在可以作爲砸了,你喜歡一個更高層的類 - 如靜態效用函數或一個更有用的「使用」對象。

你的第二個(「搗爛」)版本試圖抽象掉這種雙重查找。 但是你需要兩個快速和獨立的查找。不要強制將您在應用程序級別需要/想要的抽象強加到數據級別。

或者是這兩種方式inneficient和不正確的,是有由整數或無複製的集合連接找一找更好/更快的方法?

複製集合可能是件好事或壞事。如果它使你的代碼更加優雅和可理解,那就很好。

Premature optimization is the root of all evil

此外,有沒有對具有一個HashSet <>和一個HashMap <>包含相同類引用什麼?

我已經注意到,HashSet的<>遠在迭代比HashMap的<更高效>,並已備地圖進行查找和一組迭代,這是不好的做法?

沒有錯,在所有做這些事情只要它使你的代碼更優雅和理解。

+0

A downvote with no comment?詛咒。 – aliteralmind 2015-02-13 19:40:53

-1

創建一個包裝對象並在其中包含這兩個對象。不要忘記在創建對象時重寫hashMap()和equals()方法,因爲您打算將它用作Map中的鍵。根據兩個對象hashCode計算hasCode,並根據包含的實例計算equals。 看到這個答案:equals and hashcode

1

我肯定會建議你有兩個不同的搜索單獨的地圖。他們真的非常不同和獨立的需求。您以後也可能需要添加新的方式來查找玩家(通過名稱,位置或遊戲實例)。您不想回頭並不斷更改現有的工作數據結構。

我的建議是將你的搜索地圖封裝在玩家或連接列表的類中。這樣它們就成爲這些類中的內部實現細節,而不是類(例如)需要擔心的事情。

因此,舉例來說:

class PlayerPopulation { 
    private final List<Player> playerList = new ArrayList<>(); 
    private final Map<Player.ID, Player> playerByID = new HashMap<>(); 

    public void addPlayer(Player player) { 
     playerList.add(player); 
     playerByID.put(player.getID(), player); 
    } 

    public Player getPlayerByID(Player.ID id) { 
     return playerByID.get(id); 
    } 
} 

同樣的模式將被用於ConnectionPool(或任何你連接容器調用)。這樣,您可以輕鬆地添加新的搜索方式,而無需擔心您正在使用的地圖結構。您也可以簡單地轉換爲HashSet或其他任何東西,而不會在一個類之外受到任何影響。如果您嘗試使地圖支持多個搜索路徑,則無法這樣做。

我也將ID更改爲內部類,而不是假設Integer。我意識到你只是舉了一個例子,但認爲這是另一個好封裝的例子:你可以更改爲Long而不用更改PlayerPopulation類。

所以是的,我絕對建議不要混淆你的搜索鍵。