使用接口作为哈希图中的键
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);
}
我尝试使用接口作为 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);
}