什么时候应该为Map键创建一个类? [英] When should I create a class for a Map key?

查看:150
本文介绍了什么时候应该为Map键创建一个类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Java 6。

I'm using Java 6.

假设我有一个类,我想将其实例保存到地图中。稍后我想仅使用关键字段来检索实例。我会忽略字段修饰符,getter和setter来简化。

Suppose I have a class which I would like to save its instances into a map. Later on I would like to retrieve instances using only the "key fields". I'll ignore field modifiers, getters, and setters for conciseness.

class A {

    String field1;
    String field2;
    String field3;
    String field4;
    //more fields

    public int hashCode(){
        //uses only field1 and field2
    }

    public boolean equals(Object o){
        //uses only field1 and field2
    }
}

由于Java的标准API没有MultikeyMap,我不想使用第三方库,我可以选择

1)创建一个新类 KeyA 表示地图的关键字

2)使用 A 本身作为关键字,仅填充关键字段当我需要从地图检索对象

3)嵌套地图,例如 HashMap< String,HashMap< String,A>>

4)其他解决方法

Since Java's standard API doesn't have the MultikeyMap and I don't want to use 3rd party libraries, I have a choice of
1) creating a new class KeyA to represent the key of a map
2) use A itself as the key and populate only the "key fields" when I need to retrieve objects from a map
3) nest the maps, e.g. HashMap<String, HashMap<String, A>>
4) other workarounds

人们通常使用什么,什么时候?

What do people normally use and when?

推荐答案

鉴于您最近的编辑,您应该使用A类的实例在这种情况下的关键。将根据 equals() hashCode()的语义完成查找,因此这将导致实例仅通过关键字段检索。因此,以下代码将按照您的意图工作:

Given your recent edit, you should be fine to use instances of class A as keys in this situation. Lookups will be done based on the semantics of equals() and hashCode(), so this will cause instances to be retrieved by only the "key fields". Hence the following code would work as you intend:

final Map<A, String> map = new HashMap<A, Object>();
final A first = new A("fe", "fi", "fo", "fum");

map.put(first, "success");

// later on
final A second = new A ("fe", "fi", "foo", "bar");
System.out.println(map.get(second)); // prints "success";

说完了,你对选项2的描述让我有点担心这可能不是最明智的选择。如果创建一个 Map< A,String> ,那就是从A类实例到字符串的映射。然而,你的第二点意味着你想把它想象成从对关键字段到字符串的映射。如果你通常会根据几个原始字符串来查找价值,那么我建议反对这个。觉得错误(对我来说),创建一个假的实例的A只是为了进行查找 - 所以在这种情况下,你可能应该创建一个键类,体现一对字符串,如选项1所述(你可以甚至将这些内容嵌入到您的 A 对象中以保存关键字段)。

Having said that, your description of option 2 makes me a little concerned that this might not be the most sensible option. If you create a Map<A, String>, that's a mapping from instances of class A to strings. Yet your second point implies that you want to think of it as a mapping from pairs of key fields to strings. If you're going to usually look up values based on a couple of "raw" strings, then I'd advise against this. It feels wrong (to me), to create a "fake" instance of A just to do a lookup - so in this case, you probably should create a key class that embodies the pair of strings as described in option 1. (You could even embed instances of these within your A objects to hold the key fields).

也可以选择3。如果字符串真的在概念上是分级的,那么这可能是有道理的。例如,如果 field1 是Country,而 field2 是Town,则可以肯定地说,嵌套的地图是有意义的 - 你有一个从国家到该国家的城镇 - > A关系的地图。但是如果你的键不是以这种方式自然地组成的(比如,如果他们是(x,y)坐标),那么这再一次不是一个非常自然的方式来表示数据,单层地图从 XYPoint 的价值会更加明智。 (同样地,如果你永远不会使用两级地图,除非总是直接穿过两层,否则可能会认为一级地图仍然更有意义。)

There's a similar argument for or against option 3, too. If the strings really are conceptually hierarchical, then it might well make sense. For example, if field1 was Country, and field2 was Town, one could definitely argue that the nested maps make sense - you have a mapping from country, to the map of Town->A relations within that country. But if your keys don't naturally compose in this fashion (say, if they were (x, y) coordinates), this would again not be a very natural way to represent the data, and a single-level map from XYPoint to value would be more sensible. (Likewise, if you never use the two-level map except to always go straight through both layers, one could argue the one-level map still makes more sense.)

最后,对于选项4,如果您始终映射到 A 本身,并将密钥存储为它自己的价值(例如,如果你想规范你的 A 实例,有点像 String.intern())据指出,您根本不需要使用 Map ,而 Set 将在此处执行此工作。当您想建立不同对象之间的关系时, Map 很有用,而 Set 自动为您提供对象的唯一性,无需任何额外的概念开销。

And finally, as for option 4 -if you're always mapping to A itself, and storing the key as its own value (e.g. if you want to canonicalise your A instances, a bit like String.intern()) then as was pointed out you needn't use a Map at all, and a Set will do the job here. The Map is useful when you want to establish relationships between different objects, whereas a Set automatically gives you the uniqueness of objects without any extra conceptual overhead.

如果您将类本身用作键,如果他们的 hashCode (以及等于的行为),那么对象应该通常被用作键,随着时间的推移变化。通常这意味着键是不可变的,虽然这里你可以负担得起可变的非键字段。如果你打破这个规则,你会发现如下所示的奇怪的行为:

If you do use the class itself as a key, be warned though that objects should only generally be used as keys if their hashCode (and the behaviour of equals) won't change over time. Typically this means the keys are immutable, though here you could afford to have mutable "non-key" fields. If you were to break this rule, you'd see odd behaviour such as the following:

// Populate a map, with an A as the key
final Map<A, String> map = new HashMap<A, Object>();
final A a = new A("one", "two", "three", "four");
map.put(a, "here");

// Mutate a
a.setField1("un");

// Now look up what we associated with it
System.out.println(map.get(a)); // prints "null" - huh?
System.out.println(map.containsKey(a)); // prints "false"

这篇关于什么时候应该为Map键创建一个类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆