使用接口作为哈希映射中的键。

huangapple go评论78阅读模式
英文:

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

我不确定的是是否有一些特殊情况会破坏这个映射?是否有一种情况下,使用接口作为键会出现问题?我是否可以使用泛型更简单地实现它?

英文:

I tried to use an interface as a key in a hashMap in order to have 1 map for multiple types of keys. 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(&quot;this is bar&quot;);
}
@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&lt;Foo, Integer&gt; map = new HashMap&lt;&gt;();
static class Baz implements Foo {
String name;
public Baz(String name) {
this.name = name;
}
@Override
public void function() {
System.out.println(&quot;this is Baz&quot;);
}
@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(&quot;some name&quot;);
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?
Is there a case that having an interface as a key would break down? Could I have done it simpler using generics?

答案1

得分: 2

代码部分不要翻译,只返回翻译好的部分:

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

可能会出现比预期更多的哈希碰撞。想象一下,你有两个类都有一个int id字段,并且使用Objects.hash(id)实现了hashCode - 现在不同类的具有相同ID的对象具有相同的哈希码。如果这是预期的用例,你可以以每个类特定的方式扰动哈希,例如通过将类特定的常量混合到哈希中:

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

...

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

The only thing that's slightly out of the ordinary is that the equals methods have to compare Bar and Baz objects. When a Map only has one type of objects, the check this.getClass() == that.getClass in equals method never returns 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. 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. 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:

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

答案2

得分: 1

理论上可能存在问题,可能会因为hashCode的不同实现导致更多的哈希碰撞,从而导致性能下降,因此您需要小心,并使用实际数据进行测试。除此之外,这是一个有效的用例。

英文:

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. Other than that it is a valid use case.

huangapple
  • 本文由 发表于 2020年8月13日 18:57:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/63393671.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定