HashMap 对自定义键的行为不同 Class
HashMap behaving differently for Custom Key Class
对于以下代码片段,我看到最新的插入内容替换了旧的内容,即第 2 行中的数据替换了第 1 行中的数据。
Map<String, String> someMap = new HashMap<>();
someMap.put("A", "101A9901"); // Line 1
someMap.put("B", "102Z4902");
someMap.put("A", "103C5389"); // Line 2
但是,在使用自定义密钥 class 时,旧的会保留,新的不会添加,即第 1 行不会替换为第 2 行
Order order1 = new Order(101L, 201L, new BigDecimal(284.50), "Preparing");
Order order2 = new Order(102L, 204L, new BigDecimal(780.00), "Dispatched");
Order order3 = new Order(101L, 201L, new BigDecimal(284.50), "Cancelled");
Order order4 = new Order(104L, 207L, new BigDecimal(550.00), "Cancelled");
Order order5 = new Order(105L, 203L, new BigDecimal(320.50), "Confirmed");
Order order6 = new Order(106L, 207L, new BigDecimal(470.00), "Delivered");
Map<Order, String> orderMapAddtionalStatus = new HashMap<>();
orderMapAddtionalStatus.put(order1, "OK"); // line 1
orderMapAddtionalStatus.put(order2, "OK");
orderMapAddtionalStatus.put(order3, "OK"); // line 2
orderMapAddtionalStatus.put(order4, "OK");
orderMapAddtionalStatus.put(order5, "OK");
orderMapAddtionalStatus.put(order6, "OK");
我还覆盖了 equals 和 hashCode 方法。以下是重写的方法 -
@Override
public int hashCode() {
int result = getOrderId().hashCode();
result = 31 * result + getCustomerId().hashCode();
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Order)) return false;
Order order = (Order) o;
if (!getOrderId().equals(order.getOrderId())) return false;
return getCustomerId().equals(order.getCustomerId());
}
有人能告诉我我可能遗漏了什么吗?
如果您查看内部使用的方法 HashMap.putVal(...)
,您将看到以下内容:
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
这意味着密钥被添加到一个新节点(如果它不存在)。
但是,如果已经有一个键,则在找到节点后执行此部分:
Node<K,V> e;
... //code to find the existing node
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
如您所见,密钥未被替换,这与 put(...)
:
上的 JavaDoc 一致
If the map previously contained a mapping for the key, the oldvalue is replaced.
这说明替换的是值,而不是键。从地图的角度来看,这是一致的,因为 equals()
和 hashCode()
声明密钥相同,因此可以使用两者(现有密钥和新密钥)中的任何一个。
对于以下代码片段,我看到最新的插入内容替换了旧的内容,即第 2 行中的数据替换了第 1 行中的数据。
Map<String, String> someMap = new HashMap<>();
someMap.put("A", "101A9901"); // Line 1
someMap.put("B", "102Z4902");
someMap.put("A", "103C5389"); // Line 2
但是,在使用自定义密钥 class 时,旧的会保留,新的不会添加,即第 1 行不会替换为第 2 行
Order order1 = new Order(101L, 201L, new BigDecimal(284.50), "Preparing");
Order order2 = new Order(102L, 204L, new BigDecimal(780.00), "Dispatched");
Order order3 = new Order(101L, 201L, new BigDecimal(284.50), "Cancelled");
Order order4 = new Order(104L, 207L, new BigDecimal(550.00), "Cancelled");
Order order5 = new Order(105L, 203L, new BigDecimal(320.50), "Confirmed");
Order order6 = new Order(106L, 207L, new BigDecimal(470.00), "Delivered");
Map<Order, String> orderMapAddtionalStatus = new HashMap<>();
orderMapAddtionalStatus.put(order1, "OK"); // line 1
orderMapAddtionalStatus.put(order2, "OK");
orderMapAddtionalStatus.put(order3, "OK"); // line 2
orderMapAddtionalStatus.put(order4, "OK");
orderMapAddtionalStatus.put(order5, "OK");
orderMapAddtionalStatus.put(order6, "OK");
我还覆盖了 equals 和 hashCode 方法。以下是重写的方法 -
@Override
public int hashCode() {
int result = getOrderId().hashCode();
result = 31 * result + getCustomerId().hashCode();
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Order)) return false;
Order order = (Order) o;
if (!getOrderId().equals(order.getOrderId())) return false;
return getCustomerId().equals(order.getCustomerId());
}
有人能告诉我我可能遗漏了什么吗?
如果您查看内部使用的方法 HashMap.putVal(...)
,您将看到以下内容:
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
这意味着密钥被添加到一个新节点(如果它不存在)。 但是,如果已经有一个键,则在找到节点后执行此部分:
Node<K,V> e;
... //code to find the existing node
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
如您所见,密钥未被替换,这与 put(...)
:
If the map previously contained a mapping for the key, the oldvalue is replaced.
这说明替换的是值,而不是键。从地图的角度来看,这是一致的,因为 equals()
和 hashCode()
声明密钥相同,因此可以使用两者(现有密钥和新密钥)中的任何一个。