不幸的是,Java中的Default Set并不是为提供“get”操作而设计的,正如jschreiner所准确解释的那样。
使用迭代器找到感兴趣的元素(dacwe建议)或删除元素并更新其值重新添加元素(KyleM建议)的解决方案可能有效,但效率非常低。
重写等号的实现以使非等号对象“相等”,正如David Ogren所正确指出的那样,很容易导致维护问题。
恕我直言,使用Map作为显式替换(正如许多人建议的那样)会使代码不那么优雅。
如果目标是访问集合中包含的元素的原始实例(希望我正确理解了您的用例),这里有另一种可能的解决方案。
我个人在用Java开发客户端-服务器视频游戏时也有同样的需求。在我的例子中,每个客户机都有存储在服务器中的组件的副本,问题在于客户机何时需要修改服务器的对象。
通过互联网传递一个对象意味着客户端无论如何都有该对象的不同实例。为了将这个“复制”的实例与原始实例相匹配,我决定使用Java uuid。
因此,我创建了一个抽象类UniqueItem,它自动为其子类的每个实例提供一个随机的惟一id。
这个UUID在客户机和服务器实例之间共享,因此通过这种方式,只需使用Map就可以很容易地匹配它们。
然而,在类似的用例中直接使用Map仍然是不优雅的。有人可能会说,使用Map维护和处理可能更加复杂。
出于这些原因,我实现了一个名为MagicSet的库,它使得Map的使用对开发人员来说是“透明的”。
https://github.com/ricpacca/magicset
与原来的Java HashSet一样,MagicHashSet(库中提供的MagicSet的实现之一)使用一个支持HashMap,但是它使用元素的UUID作为键,使用元素本身作为值,而不是将元素作为键和虚拟值作为值。与普通HashSet相比,这不会导致内存使用的开销。
此外,MagicSet可以完全作为Set使用,但有一些提供额外功能的方法,如getFromId()、popFromId()、removeFromId()等。
使用它的唯一要求是您想要存储在MagicSet中的任何元素都需要扩展抽象类UniqueItem。
下面是一个代码示例,设想从MagicSet中检索一个城市的原始实例,给定该城市的另一个实例,该实例具有相同的UUID(甚至只有它的UUID)。
class City extends UniqueItem {
// Somewhere in this class
public void doSomething() {
// Whatever
}
}
public class GameMap {
private MagicSet<City> cities;
public GameMap(Collection<City> cities) {
cities = new MagicHashSet<>(cities);
}
/*
* cityId is the UUID of the city you want to retrieve.
* If you have a copied instance of that city, you can simply
* call copiedCity.getId() and pass the return value to this method.
*/
public void doSomethingInCity(UUID cityId) {
City city = cities.getFromId(cityId);
city.doSomething();
}
// Other methods can be called on a MagicSet too
}