假设我有理由要求通过多种值类型快速查找类实例,为了解释这一点,我将以游戏服务器为例。
假设服务器使用静态标识号处理用户。此号码用于与特定玩家进行交流和互动(即:私人聊天,交易请求,战斗,公会邀请等)。
根据我目前的经验,这需要经常使用他们的识别号码查看玩家,最好的方法就是这样:(如果我错了,请纠正我。)
HashMap<Integer, Player>
然而,当处理网络时,很多时候我还需要让玩家与网络会话相关联,或者“插座”,因为有些人可能更熟悉。看起来像这样:
HashMap<Connection, Player>
所以我想弄清楚的是,我应该走这条路吗?
HashMap<Integer, Player> playersById;
HashMap<Connection, Player> playersByConnection;
或者我应该多做一些“捣乱”,如下:
HashMap<Object[], Player> playersOnline;
并将Object[0]
作为整数,Object[1]
作为连接,然后使用查找期间所需的那个。
或者这两种方式都不合适且不正确,是否有更好/更快的方式通过Integer或Connection查找它们而不重复收集?
任何见解都会非常感激。
编辑另外,是否有任何反对让HashSet<>
和HashMap<>
包含相同的类引用?我注意到HashSet<>
在迭代方面比HashMap<>
更有效率,并且一直保持一个Map for lookup和一个Set for iterating,这是不好的做法?
答案 0 :(得分:1)
我肯定会建议你为两个不同的搜索分别制作地图。他们真的是完全不同的独立需求。您也可能稍后需要添加新方法来查找玩家(按名称,按位置或游戏实例)。您不希望必须返回并继续更改现有的工作数据结构。
我的建议是将两个搜索地图封装在包含玩家或连接列表的类中。这样,它们只是这些类中的内部实现细节,而不是Player
类(例如)需要担心的内容。
所以,例如:
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
类。
所以是的,我绝对建议不要将搜索键混合在一起。
答案 1 :(得分:-1)
首先,我必须提到宝贵的What Collection should I use流程图。
绝对将两个HashMap /非“smashed”版本用于两个独立的地图,然后在更高级别的类中将其抽象出来,可以随意打碎 - 例如使用静态实用函数或更有用“用法“对象。
你的第二个(“粉碎”)版本试图抽象出这个双重查找。 但是你需要两个快速且独立的查找。不要强迫你在应用程序级别需要/想要的抽象到数据级别。
或者这两种方式都不合适且不正确,是否有更好/更快的方式通过Integer或Connection查找它们而不复制集合?
复制集合可能是好事还是坏事。如果它使你的代码更优雅和可理解,那就很好。
Premature optimization is the root of all evil。
此外,还有什么反对拥有HashSet&lt;&gt;和HashMap&lt;&gt;包含相同的类引用?
我注意到HashSet&lt;&gt;迭代的效率远远高于HashMap&lt;&gt;并且一直保持一个Map for lookup和一个Set for iterating,这是不好的做法吗?
只要它使你的代码更优雅和易懂,做任何这些事情都没有错。
答案 2 :(得分:-1)
创建一个包装器对象并在其中包含这两个对象。不要忘记在创建对象时覆盖hashMap()和equals()方法,因为您计划将其用作Map中的键。根据两个对象hashCode计算hasCode,并根据包含的实例计算equals。 请参阅此答案:equals and hashcode