使用接口作为哈希图中的键

Using an interface as a key in a hashmap

我尝试使用接口作为 hashMap 中的键,以便为多种类型的键创建 1 个映射。以下似乎有效。

interface Foo {
        void function();
}
static class Bar implements Foo {

      private int id;
    
      public Bar(int id) {
          this.id = id;
      }
    
      @Override
      public void function() {
          System.out.println("this is bar");
      }
    
      @Override
      public boolean equals(Object o) {
           if (this == o) return true;
           if (o == null || getClass() != o.getClass()) return false;
           Bar bar = (Bar) o;
           return id == bar.id;
       }
    
       @Override
       public int hashCode() {
          return Objects.hash(id);
       }
}
    
public static Map<Foo, Integer> map = new HashMap<>();
    
    
     
static class Baz implements Foo {
    String name;
    public Baz(String name) {
        this.name = name;
    }

    @Override
    public void function() {
       System.out.println("this is Baz");
    }
    @Override
    public boolean equals(Object o) {
       if (this == o) return true;
       if (o == null || getClass() != o.getClass()) return false;
       Baz baz = (Baz) o;
       return name.equals(baz.name);
    }

    @Override
    public int hashCode() {
       return Objects.hash(name);
    }
}

public static void main(String[] args) {
    Bar bar = new Bar(123);
    Baz baz = new Baz("some name");

    map.put(bar, 10);
    map.put(baz, 20);
  
    System.out.println(map.get(bar));
 }

我不确定是否有一些极端情况会破坏这张地图?
是否存在将接口作为密钥会崩溃的情况?我可以使用泛型做得更简单吗?

理论上,由于 hashCode 的不同实现,可能存在更多哈希冲突导致性能不佳的问题,因此您需要小心,并使用真实数据进行测试。除此之外,它是一个有效的用例。

唯一有点不同寻常的是 equals 方法必须比较 Bar 和 Baz 对象。当 Map 只有一种类型的对象时,equals 方法中的检查 this.getClass() == that.getClass 永远不会 returns false。不过你已经正确地实现了这一点,所以你没有什么可担心的。

您遇到的哈希冲突可能比您预期的要多。假设您有两个 classes,它们都有一个 int id 字段并使用 Objects.hash(id) 实现 hashCode - 现在具有相同 ID 的不同 classes 的对象具有相同的哈希码。如果这种用例是预期的,您可以以每个 class 独有的方式扰乱哈希,例如通过将 class-specific 常量混合到哈希中:

@Override
public int hashCode() {
   return Objects.hash(1, id);
}

...

@Override
public int hashCode() {
   return Objects.hash(2, name);
}