【发布时间】:2012-09-28 06:51:49
【问题描述】:
我想存储绑定到名称 + 数字的值。 比如,(John,1) (RED) and (John,2) (BLUE) and (Elize,1) (GREEN) 那么我怎样才能存储组合唯一的 2 个键呢?
【问题讨论】:
标签: java hashmap key-value unique-key
我想存储绑定到名称 + 数字的值。 比如,(John,1) (RED) and (John,2) (BLUE) and (Elize,1) (GREEN) 那么我怎样才能存储组合唯一的 2 个键呢?
【问题讨论】:
标签: java hashmap key-value unique-key
创建一个表示复合键的新类型(此处为名称和数字)。您需要覆盖hashCode() 和equals(),我强烈建议您将类型设置为不可变。例如:
public final class NameIntPair {
private final int intValue;
private final String name;
public NameIntPair(int intValue, String name) {
this.intValue = intValue;
this.name = name;
}
@Override
public int hashCode() {
int hash = 17;
hash = hash * 31 + intValue;
hash = hash * 31 + (name == null ? 0 : name.hashCode());
return hash;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof NameIntPair)) {
return false;
}
if (this == obj) {
return true;
}
NameIntPair other = (NameIntPair) obj;
return other.intValue == intValue && Objects.equal(other.name, name);
}
}
为了方便起见,我使用 Guava 中的 Objects.equal 来避免显式的无效性检查 - 如果您不使用 Guava,则必须在代码中使用等效项或处理无效性。或者,您可能希望防止空名称,在构造函数中验证它。
【讨论】:
如果我确定组合的唯一性并且键对象易于字符串化,我将使用字符串连接。我可能会使用特殊字符来连接键(如“John#1”和“John#2”)。
如果我不确定,我会使用Guava's Table:
通常,当您尝试索引多个键时 时间,你会得到类似 Map(FirstName, Map(LastName, Person)),使用起来丑陋且尴尬。番石榴 提供了一个新的集合类型 Table,它支持这个用例 对于任何“行”类型和“列”类型
所以表是
关联有序键对的集合,称为行键 和一个列键,只有一个值。
【讨论】:
像这样定义您的特定 Key 类:
public class Key {
final String name;
final int number;
public Key(String name, int number) {
this.name = name;
this.number = number;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result
+ ((name == null) ? 0 : name.hashCode());
result = prime * result + number;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Key other = (Key) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (number != other.number)
return false;
return true;
}
private Test getOuterType() {
return Test.this;
}
}
重要的一点是确保您遵守 equals 和 hashCode 的约定,以使您的集合(使用密钥的任何标准集合)按预期工作。
这里我只使用了 Eclipse 生成的生成方法,但也有许多动态实用程序(例如在 Guava 中)可以帮助您解决这个问题。
【讨论】:
还有适合这种情况的连接键的简单替代方法:
public static String getKey(String name, int number) {
return name + number;
}
如果名称不太长,则字符串连接的开销不会大于其他答案中建议的创建复合键对象的开销。
【讨论】: