我们可以创建哈希映射键单例吗?

Can we create hashmap key singleton?

前几天我在面试,问到hashmap的时候哑口无言 这里有几个

能把key做成单例吗?

我们能否使 hashmap 的键可变或不可变,您会选择哪一个,为什么?

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

遵循的 link

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

请多多关照。

嗯,这很有趣。

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

我们有两个单例对象class

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

场景 1:如果我们使用 Singleton 键创建 HashMap 那么

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

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

场景 2:如果一个对象只是更改 Singleton 字段的值会怎么样 class

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 class 作为密钥。现在很清楚,你不能在 HashMap 中使用 Singleton class 作为键。

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

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

  1. Can we make key as singleton?

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

  1. Can we make key of hashmap mutable or immutable which one you will choose and why?

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

对于 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

这自然可以理解为,object key里面的值作为map的key。

现在 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 和值 44 现在如何访问映射中的不同值...k2 没有发生变化,但随着时间的推移检索到的值不一样!

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