【问题标题】:Can we create hashmap key singleton?我们可以创建 hashmap 键单例吗?
【发布时间】:2020-03-30 01:35:02
【问题描述】:

前几天我正在接受采访,当对 hashmap 进行提问时,我无言以对 这里有几个

我们可以将键设为单例吗?

我们可以让 hashmap 的 key 可变或不可变,你会选择哪一个?为什么?

对于第二个问题,我通过网络搜索,发现如果我们正在创建密钥,它应该是不可变的,否则数据保存在第一个密钥上,然后稍后修改,如果我们再次尝试获取它,它将返回 null,因此对象将丢失。 这是我为这个Custom Key Hashmap 关注的链接

第一个问题呢,我们可以创建 Hashmap 键单例吗?根据我的说法,如果我们创建键单例,那么如果我们尝试使用单例键添加,我们将失去使用相同键的 hashmap 的能力将替换数据。

请给它一些亮点。

【问题讨论】:

  • 老实说,我不明白“我们可以将密钥设为单例吗?”题。这是什么意思?
  • @Holger 如果键值是通过单例模式生成的。
  • 如果键是通过单例生成的,那么地图中当然只能存在一个(键,值)对,因为(键,值)对必须通过键区分(键是 )。
  • HashMap 与用于键的对象的类设计之间没有关系。而且,不,这也不影响HashMap 可以存储的内容。看,HashMap<Object,Object> map = new HashMap<>(); map.put(Runtime.getRuntime(), ""); map.put(FileSystem.getDefault(), 42);,我已经存储了两个单例作为键......
  • @Holger 我不确定这是不是问题,但至少在某些采访中这可能是一个很好的答案!

标签: java java-8 hashmap concurrenthashmap linkedhashmap


【解决方案1】:

一个非常有趣的问题,因为它需要了解什么是地图......

  1. 我们可以将密钥设为单例吗?

如果您使用单例模式生成键,那么显然只会创建一个键,然后地图中一次只会出现一对 (key,value)。这就是说,我们显然更改了与唯一可能的键关联的值。这个答案当然是肯定的,key 的本质对地图来说并不重要,但这会导致地图愚蠢或不是很有用(至少给我一个令人信服的例子)。

  1. 我们能否将 hashmap 的键设置为可变或不可变,您将使用哪一个 选择,为什么?

选择不可变的!否则,根据您选择的具体地图,您将遇到严重的问题。

对于HashMap 等:

import java.util.*;

class K {
  private int value;
  public boolean equals(Object o) { K k = (K)o; return k.value==value; }
  public int hashCode() { return value; }
  public K(int v) { this.value = v; }
  public void setValue(int v) { this.value = v; }
  public String toString() { return ""+value; }
}

public class Test {
  public static void main(String []a) {
    HashMap<K,String> m = new HashMap<K,String>();
    K k1 = new K(33);
    m.put(k1,"Here I am");
    K k2 = new K(44);
    m.put(k2,"Here it is");
    System.out.println("k1: "+k1+" "+m.get(k1));
    System.out.println("k2: "+k2+" "+m.get(k2));
    k1.setValue(666);
    System.out.println("k1: "+k1+" "+m.get(k1));

    k1.setValue(44);
    System.out.println("k2: "+k2+" "+m.get(k2));
    k1.setValue(666);
    System.out.println("k1: "+k1+" "+m.get(k1));
    k1.setValue(33);
    System.out.println("k1: "+k1+" "+m.get(k1));
  }
}

将产生:

k1: 33 Here I am
k2: 44 Here it is
k1: 666 null
k2: 44 Here it is
k1: 666 null
k1: 33 Here I am

这自然是可以理解的,对象键中的值作为映射的键。

现在有了TreeMap,情况就不同了:

import java.util.*;

class K implements Comparable<K> {
  private int value;
  public boolean equals(Object o) { K k = (K)o; return k.value==value; }
  public int hashCode() { return value; }
  public K(int v) { this.value = v; }
  public void setValue(int v) { this.value = v; }
  public String toString() { return ""+value; }
  public int compareTo(K k) { return Integer.compare(value,k.value); }
}

public class Test2 {
  public static void main(String []a) {
    TreeMap<K,String> m = new TreeMap<K,String>();
    K k1 = new K(33);
    m.put(k1,"Here I am");
    K k2 = new K(44);
    m.put(k2,"Here it is");
    System.out.println("k1: "+k1+" "+m.get(k1));
    System.out.println("k2: "+k2+" "+m.get(k2));
    k1.setValue(666);
    System.out.println("k1: "+k1+" "+m.get(k1));

    k1.setValue(44);
    System.out.println("k2: "+k2+" "+m.get(k2));
    k1.setValue(666);
    System.out.println("k1: "+k1+" "+m.get(k1));
    k1.setValue(33);
    System.out.println("k1: "+k1+" "+m.get(k1));
  }
}

将产生:

k1: 33 Here I am
k2: 44 Here it is
k1: 666 Here I am
k2: 44 Here I am
k1: 666 Here I am
k1: 33 Here I am

看看 k2 和 value 44 现在如何访问映射中的不同值...k2 没有变异,但检索到的值随着时间的推移而不同!

因此,永远不要使用可变键...

【讨论】:

  • 您的最后一行是否使用不可变有点令人困惑?
【解决方案2】:

嗯,这很有趣。

首先是Java中的Singleton Class,是一个一次只能有一个对象(类的一个实例)的类。 这意味着多个对象之间只共享一个副本。

我们有两个 Singleton 类的对象

Singleton x = Singleton.getInstance(); 
Singleton y = Singleton.getInstance(); 

场景1:如果我们用单例键创建HashMap,那么

Map<SingletonClass, Interger> map = new HashMap<>();
        map.put(x, 10);
        map.put(y, 20);

你认为输出会是什么, 在这种情况下,大小将为 1,而 10 被 20 覆盖。对吗? 同一个对象有同样的HashCode和equals方法实现。

场景2:如果一个对象只是改变了Singleton类的字段值

Map<SingletonClass, Interger> map = new HashMap<>();
    map.put(x, 10);
    y.s = (y.s).toUpperCase(); // s is a String field in Singleton Class
    map.put(y, 20);

在这种情况下,大小为 1。x 和 y 的哈希码相同。

所以,总是有 1 个对象会一次又一次地覆盖该值。

你知道为什么我们使用 Immutable 类作为键。现在很清楚,不能将 HashMap 中的 Singleton 类用作键。

即使您将 HashCode 对象作为键覆盖,也会作为引用存储在 Map 中。所以如果你改变它的实现,它会在执行 Singleton 类的 hashcode 方法时反映在 Map 中。 是的,您可以覆盖 equals 方法,但它只会增加 HashMap 中的冲突情况。

【讨论】:

    猜你喜欢
    • 2014-06-29
    • 2012-04-22
    • 2017-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-25
    • 1970-01-01
    • 2021-12-18
    相关资源
    最近更新 更多