【问题标题】:Store java.util.Date as key in a Map based on reference equality instead of "value" equality基于引用相等而不是“值”相等将 java.util.Date 存储为 Map 中的键
【发布时间】:2014-12-31 10:38:54
【问题描述】:

我想构建一个 Date 对象的 HashMap,所以每当我有两个具有相同 Date 值(日、月、年、..)的不同 Date 对象时,Hashmap 不会用新值替换过去的值。

例子:

    Date x = new Date();
    Date y = new Date();

    HashMap<Date,Integer> hm = new HashMap<Date,Integer>();
    hm.put(x,1);
    hm.put(y,3);

    System.out.println(hm.get(x));
    System.out.println(hm.get(y));

在此示例中,它们都打印 3。我想确保它们打印 1 然后 3。

我考虑过将 Hashmap 中的键值作为每个日期的对象引用(因为它们会有所不同),那么我该如何强制对象这样做呢?

或者有更好的方法吗?

【问题讨论】:

  • 请阅读您的问题并尝试重新编写。我无法理解你想要什么
  • 您的HashMap 有什么价值?您如何将它们视为两个独特的对象?
  • 您在寻找允许重复键的地图吗?
  • HashMap&lt;Date, X&gt; 不能按预期工作吗? Date.hashCode 和 equals 应该明确定义。你可以转储地图的entrySet()
  • 两个 Date 对象将生成相同的日期,x 和 y 将相同。

标签: java date dictionary collections


【解决方案1】:

您应该使用java.util.IdentityHashMap 来执行此任务。这样您就可以拥有equals,但您的Map 中有不同的对象。

编辑: 你的例子:

Date x = new Date();
Date y = new Date();

Map<Date,Integer> hm = new IndentityHashMap<Date,Integer>();
hm.put(x,1);
hm.put(y,3);
assert hm.size() == 2: hm.size();

正如@BoristheSpider 所指出的,当您失去对原始对象的引用时,这可能不是最好的数据结构。在这种情况下,MultiMap(如guava's)或Entrys/Pairs/Tuples 的List 可能是更好的选择,具体取决于用例。 (前者适用于您想要所有值属于某个equals 键的情况,后者是访问所有键/值对,但不通过键搜索。)

如果您只是想将Map 用作“数组”并随机访问某些或所有(存储的)密钥,那么IdentityHashMap 是一个不错的选择。

【讨论】:

  • @AerRayes 请注意,如果您丢失了原始引用,则永远无法从 IdentityHashMap 检索 Object
  • @BoristheSpider 我认为您可以遍历其中的entrySet()/keySet() 并重新获得原始引用。
  • @GáborBakos 仅当您以某种方式找出您想要重新获得的 什么 时。如果没有可比较的参考,您如何检查哪个是原始参考?
  • @GáborBakos 我知道。但是看看 OP 的例子 - 问题是 Date 对象 are .equals 这正是 为什么 HashMap 不起作用。因此,如果您的评论有任何优点,那么 IdentityHashMap 是错误的构造。
【解决方案2】:

更好的解决方案是使用唯一的时间戳。这将确保您可以通过具有相同的时间戳来检索值。

private static final AtomicLong MILLIS = new AtomicLong();

public static Date newDate() {
    long now = System.currentTimeMillis();
    for(;;) {
        long prev = MILLIS.get();
        if (prev >= now)
            now = prev + 1;
        if (MILLIS.comapreAndSet(prev, now))
            return new Date(now);
    }
}

如果你使用这个日期工厂,每个数据都是唯一的,并且尽可能接近实际时间。

Date x = newDate();
Date y = newDate();

Map<Date,Integer> hm = new HashMap<>();
hm.put(x,1);
hm.put(y,3);

System.out.println(hm.get(x));
System.out.println(hm.get(y));

【讨论】:

  • 或者使用 Java 8 中的 Instant 类(如果可能的话)——它具有纳米精度,因此应该提供唯一性。
  • @BoristheSpider 应该但可能不会在具有微秒分辨率的系统上。
  • @PeterLawrey 我认为不应该只存储新的Dates。在高度并发的情况下,很难有效且正确地调整日期以存储。它也修改了日期。你认为这是一个明智的选择吗?即使您有原始 Dates 的参考资料,您也无法获取这些值。也许我误解了你的建议。
  • @GáborBakos 我认为这是一个不错的选择,这就是我建议它的原因。它存储尽可能多的数据并且高度并发,尽管每秒有超过 1000 个日期会是一个问题。如果您使用原始的 Date 对象,则可以将它们用作键,这就是我声称我提供的代码示例可以工作的原因。
猜你喜欢
  • 2011-08-14
  • 1970-01-01
  • 1970-01-01
  • 2018-12-16
  • 2012-05-11
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 2012-10-14
相关资源
最近更新 更多