无法从 Hashmap 获取对象的值,即使它 returns 具有相同的哈希码
Unable to get value for an object from Hashmap, even though it returns the same hashcode
//覆盖其hashcode后无法获取hashmap中对象的值
//这是我根据项目名称
生成hascode的项目class
public class Item {
private String name;
private Long id;
private double price;
//Constructor
public Item(String name, Long id, double price) {
this.name = name;
this.id = id;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
//Generating hashcode based on name comparing if item id are //same
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object obj) {
return ((Item) obj).id ==(id);
}
@Override
public String toString() {
return "Item {" +
" name='" + name + '\'' +
", id=" + id +
", price=" + price +
'}';
}
//Here there are items but when i pass the exact same item with exact //credentials i get null while checking how many items are there using Hashmap.
public class Warehouse {
Map<Item, Integer> itemList = new HashMap<>();
List<Drone> drones = new ArrayList<>();
private Drone drone;
private String sourceAddress;
private Address address;
public Warehouse(Address address) {
this.address = address;
Item item = new Item("PlayStation 4 pro", (long) 100, 42000);
Item item1 = new Item("X box one S", (long) 200, 40000);
Item item2 = new Item("Apple Macbook Pro", (long) 500, 82000);
Item item3 = new Item("Dell Xps Laptop", (long) 1000, 92000);
Item item4 = new Item("iPhone 7 plus", (long) 2000, 72000);
itemList.put(item, 10);
itemList.put(item1, 20);
itemList.put(item2, 40);
itemList.put(item3, 50);
itemList.put(item4, 20);
}
public Drone getDrone() {
return new Drone();
}
public void setDrone(Drone drone) {
this.drone = drone;
System.out.println("Drone # " + drone.getDroneID() + " has arrived at the warehouse " + address);
}
public Address getAddress() {
return address;
}
public ArrayList<Item> getItemList() {
return (ArrayList<Item>) itemList;
}
//Setting the item
public void setItem(Item item) {
Integer num = itemList.get(item);
if (num == null) {
num = 0;
}
this.itemList.put(item, ++num);
}
//这就是我面临的问题,如果我查询 hashmap 中的相同项目,它 returns me null,Item even returns 相同的 hashcode
public Item removeItem(Item item) {
Integer num = itemList.get(item);
//## Issue is i get null in num
if(null!= num||num!=0 ){
itemList.put(item,num-1);
}
System.out.println(item);
return item;
}
}
您的对象的 hashCode
使用了 name
属性,但是您的 equals
使用了 id
属性。这违反了合同。 equals
returns 为真的对象必须具有相同的 hashCode
.
HashMap
使用 hashCode
和 equals
来定位键。首先,它根据 hashCode
在 HashMap
中定位一个 bin。然后它使用 equals
遍历 bin 中的所有条目以找到您要查找的密钥。当 hashCode
不匹配 equals
时,您认为相等的两个对象可能会映射到不同的 bin,因此使用 map.contains(key)
查找存储在 Map
中的键会失败。
我认为用id
作为平等的标准更有意义,所以我会写:
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Item))
return false;
return ((Item) obj).id.equals(id);
}
请注意,我使用 equals
来比较 id
。将对象与 ==
(在您的情况下为 Long
s)进行比较通常是错误的。
此外,您可能希望在将 obj
转换为 Item
之前检查其类型,如果类型不正确则返回 false,从而使 equals
方法更安全匹配。
P.S。根据您的新代码,您还有另一个问题:
这个条件:
if(null!= num||num!=0 )
要么为真(如果 num != null
),要么抛出一个 NullPointerException
(如果 num
为 null
)。
因此,如果它已经在 Map
中,它只会将 item
放在 Map
中。不清楚所需的逻辑是什么,但看起来不对。
where/which 个条目的决定是根据您的 hashcode
做出的。但是该存储桶中可能有 许多 个条目。
所以调用 equals
来识别您感兴趣的条目。由于 hashcode
和 equals
是不相关的(不同的属性),这会导致不一致。
所以假设你有这个:
EntryA (hashCode = 42, id = 2)
EntryB (hashCode = 44, id = 2)
这些条目 equal
基于 id
;但由于它们有不同的 hashcodes
,它们将在 HashMap 的不同部分进入 不同的桶 。
所以现在您将在 Map 中有两个相同的条目(根据 equals)——这就是为什么 hashcode 和 equals 必须 彼此一致.
public class Item {
private String name;
private Long id;
private double price;
//Constructor
public Item(String name, Long id, double price) {
this.name = name;
this.id = id;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
//Generating hashcode based on name comparing if item id are //same
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object obj) {
return ((Item) obj).id ==(id);
}
@Override
public String toString() {
return "Item {" +
" name='" + name + '\'' +
", id=" + id +
", price=" + price +
'}';
}
//Here there are items but when i pass the exact same item with exact //credentials i get null while checking how many items are there using Hashmap.
public class Warehouse {
Map<Item, Integer> itemList = new HashMap<>();
List<Drone> drones = new ArrayList<>();
private Drone drone;
private String sourceAddress;
private Address address;
public Warehouse(Address address) {
this.address = address;
Item item = new Item("PlayStation 4 pro", (long) 100, 42000);
Item item1 = new Item("X box one S", (long) 200, 40000);
Item item2 = new Item("Apple Macbook Pro", (long) 500, 82000);
Item item3 = new Item("Dell Xps Laptop", (long) 1000, 92000);
Item item4 = new Item("iPhone 7 plus", (long) 2000, 72000);
itemList.put(item, 10);
itemList.put(item1, 20);
itemList.put(item2, 40);
itemList.put(item3, 50);
itemList.put(item4, 20);
}
public Drone getDrone() {
return new Drone();
}
public void setDrone(Drone drone) {
this.drone = drone;
System.out.println("Drone # " + drone.getDroneID() + " has arrived at the warehouse " + address);
}
public Address getAddress() {
return address;
}
public ArrayList<Item> getItemList() {
return (ArrayList<Item>) itemList;
}
//Setting the item
public void setItem(Item item) {
Integer num = itemList.get(item);
if (num == null) {
num = 0;
}
this.itemList.put(item, ++num);
}
//这就是我面临的问题,如果我查询 hashmap 中的相同项目,它 returns me null,Item even returns 相同的 hashcode
public Item removeItem(Item item) {
Integer num = itemList.get(item);
//## Issue is i get null in num
if(null!= num||num!=0 ){
itemList.put(item,num-1);
}
System.out.println(item);
return item;
}
}
您的对象的 hashCode
使用了 name
属性,但是您的 equals
使用了 id
属性。这违反了合同。 equals
returns 为真的对象必须具有相同的 hashCode
.
HashMap
使用 hashCode
和 equals
来定位键。首先,它根据 hashCode
在 HashMap
中定位一个 bin。然后它使用 equals
遍历 bin 中的所有条目以找到您要查找的密钥。当 hashCode
不匹配 equals
时,您认为相等的两个对象可能会映射到不同的 bin,因此使用 map.contains(key)
查找存储在 Map
中的键会失败。
我认为用id
作为平等的标准更有意义,所以我会写:
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Item))
return false;
return ((Item) obj).id.equals(id);
}
请注意,我使用 equals
来比较 id
。将对象与 ==
(在您的情况下为 Long
s)进行比较通常是错误的。
此外,您可能希望在将 obj
转换为 Item
之前检查其类型,如果类型不正确则返回 false,从而使 equals
方法更安全匹配。
P.S。根据您的新代码,您还有另一个问题:
这个条件:
if(null!= num||num!=0 )
要么为真(如果 num != null
),要么抛出一个 NullPointerException
(如果 num
为 null
)。
因此,如果它已经在 Map
中,它只会将 item
放在 Map
中。不清楚所需的逻辑是什么,但看起来不对。
where/which 个条目的决定是根据您的 hashcode
做出的。但是该存储桶中可能有 许多 个条目。
所以调用 equals
来识别您感兴趣的条目。由于 hashcode
和 equals
是不相关的(不同的属性),这会导致不一致。
所以假设你有这个:
EntryA (hashCode = 42, id = 2)
EntryB (hashCode = 44, id = 2)
这些条目 equal
基于 id
;但由于它们有不同的 hashcodes
,它们将在 HashMap 的不同部分进入 不同的桶 。
所以现在您将在 Map 中有两个相同的条目(根据 equals)——这就是为什么 hashcode 和 equals 必须 彼此一致.