简体   繁体   English

在 hashmap 中使用接口作为密钥

[英]Using an interface as a key in a hashmap

I tried to use an interface as a key in a hashMap in order to have 1 map for multiple types of keys.我尝试使用接口作为hashMap中的键,以便为多种类型的键提供 1 个 map。 The following seems to work.以下似乎有效。

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));
 }

What I am not sure about is if there is some corner case that would break this map?我不确定是否有一些角落案例会破坏这个 map?
Is there a case that having an interface as a key would break down?是否存在将接口作为键会崩溃的情况? Could I have done it simpler using generics?我可以使用 generics 做得更简单吗?

The only thing that's slightly out of the ordinary is that the equals methods have to compare Bar and Baz objects.唯一有点不寻常的是equals方法必须比较Bar和Baz对象。 When a Map only has one type of objects, the check this.getClass() == that.getClass in equals method never returns false.当 Map 只有一种类型的对象时,equals 方法中的this.getClass() == that.getClass的检查永远不会返回 false。 You have implemented this correctly though, so you don't have anything to worry about.不过,您已经正确地实现了这一点,因此您无需担心任何事情。

You may get more hash collisions than you expect.您可能会遇到比您预期更多的 hash 冲突。 Imagine you have two classes that both have an int id field and implement hashCode with Objects.hash(id) - now objects of different classes with the same ID have the same hash code.假设您有两个类,它们都有一个 int id 字段并使用Objects.hash(id)实现 hashCode - 现在具有相同 ID 的不同类的对象具有相同的 hash 代码。 If this use case is expected, you can perturb the hash in a way unique to each class, for example by mixing a class-specific constant to the hash:如果预期会出现此用例,您可以以每个 class 独有的方式干扰 hash,例如通过将特定于类的常量与 hash 混合:

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

...

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

In theory there could be problems with potentially more hash collisions leading to bad performance due to different implementations of hashCode , so you need to be careful, and test it with the real data.理论上,由于hashCode的不同实现,可能存在更多 hash 冲突导致性能不佳的问题,因此您需要小心,并使用真实数据进行测试。 Other than that it is a valid use case.除此之外,它是一个有效的用例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM