Java hashmap - 基于两个不同类型对象的键

时间:2015-06-26 15:12:50

标签: java hashmap

我想编写一个Java类来根据相关的时间戳计算某些规则(对于每个rueleId)的出现次数。

例如,

输入:

{"ruleId": "1", "timestamp":"Thu Jun 18 16:25:56 PDT 2015"}
{"ruleId": "1", "timestamp":"Thu Jun 18 16:25:56 PDT 2015"}
{"ruleId": "2", "timestamp":"Thu Jun 18 16:25:56 PDT 2015"}
{"ruleId": "2", "timestamp":"Thu Jun 18 16:25:56 PDT 2015"}
{"ruleId": "2", "timestamp":"Thu Jun 18 16:27:56 PDT 2015"}

输出:

timestamp: "Thu Jun 18 16:25:56 PDT 2015", ruleId: "1", count: 2
timestamp: "Thu Jun 18 16:25:56 PDT 2015", ruleId: "2", count: 2
timestamp: "Thu Jun 18 16:27:56 PDT 2015", ruleId: "2", count: 1

我想我可以使用HashMap。

这里的关键我认为是基于ruleId(类型:字符串)和时间戳(类型:日历),其值为计数。

如何根据两个不同的对象获得密钥? 我的方法有误吗?

2 个答案:

答案 0 :(得分:4)

您必须创建复合键

public final class CompositeKey {
    private final String ruleType;
    private final Calendar timeStamp;

    public CompositeKey(String ruleType, Calendar timeStamp) {
        this.ruleType = Objects.requireNonNull(ruleType);
        this.timeStamp = (Calendar) Objects.requireNonNull(timeStamp).clone();
    }

    public String ruleType() { return ruleType; }
    public Calendar timeStamp() { return (Calendar) timeStamp.clone(); }

    @Override public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        CompositeKey other = (CompositeKey) obj;
        return Objects.equals(ruleType, other.ruleType) && Objects.equals(timeStamp, other.timeStamp);
    }

    @Override public int hashCode() { return Objects.hash(ruleType, timeStamp); }
}

当用作HashMap中的键时,必须修改对象。因此它必须是不可改变的。上面的类通过最终,不提供setter和克隆时间戳来实现这个目标(因为Calendar不是不可变的)。

另一个非常重要的事情是,关键类必须提供适当的equalshashCode方法。

使用该类后,您可以在HashMap

中使用它
String ruleType = ...
Calendar timeStamp = ...
CompositeKey key = new CompositeKey(ruleType, timeStamp);
Object value = ...

Map<CompositeKey, Object> map = new HashMap<>();
map.put(key, value);

答案 1 :(得分:2)

HashMap只有一种密钥类型。这就是它的方式。

所以你有两个选择。

生成一个充当HashMap Key的密钥字符串。在你的情况下,这是可以轻松完成的事情,它可能只是你需要的一切。您可以生成"time:" + timeStamp.toString() + "-rule:" + ruleId之类的内容并将其用作关键字。它可以解决你的问题。

第二种方法稍微复杂一点,但是如果你想再次分离你在密钥中使用的值或者你有更复杂的值作为关键值,则更适合。我们的想法是创建一个新类,作为键值的载体。

对于第二个想法,重要的是您覆盖运营商对象的hashCodeequals功能,以使其与HashMap一起正常运行。

基本上你需要这样的东西:

public class Carrier {
    private final Calendar timestamp;
    private final String ruleId;

    public Carrier(Calendar timestamp, String ruleId) {
        this.timestamp = timestamp;
        this.ruleId = ruleId;
    }

    @Override
    public int hashCode() {
        int hash = 1;
        hash = hash * 17 + timestamp.hashCode();
        hash = hash * 17 + ruleId.hashCode();
        return hash;
    }

    @Override 
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceOf Carrier) {
            return false;
        }

        Carrier other = (Carrier) obj;
        return Objects.equals(ruleId, other.ruleId) && Objects.equals(timestamp, other.timestamp);
    }
}