无法从Hashmap获取对象的值,即使它返回相同的哈希码

时间:2017-05-26 06:51:42

标签: java oop java-8 hashmap equals

enter image description here //在覆盖其哈希码后,无法获取hashmap中对象的值 //这是我根据项目名称生成hascode的项目类

 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它返回null,Item甚至返回相同的哈希码

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

            }

2 个答案:

答案 0 :(得分:5)

您的对象hashCode使用了name属性,但您的equals使用了id属性。这违反了合同。 equals返回true的对象必须具有相同的hashCode

HashMap同时使用hashCodeequals来查找密钥。首先,它根据HashMaphashCode内找到一个bin。然后,它使用equals遍历bin中的所有条目,以找到您要查找的密钥。当hashCodeequals不匹配时,您认为相同的两个对象可能会映射到不同的二进制位,因此使用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)进行比较通常是错误的。

此外,您可能希望通过在将equals投射到obj之前检查Item的类型来使if(null!= num||num!=0 ) 方法更安全,如果类型不匹配则返回false。

P.S。根据您的新代码,您还有另一个问题:

这个条件:

num != null

将为真(如果NullPointerException)或抛出num(如果nullitem)。

因此,如果Map已经在Map中,它只会将babun放入virtualenv。目前尚不清楚所需的逻辑是什么,但它看起来不正确。

答案 1 :(得分:3)

根据您的hashcode决定 / 对某些条目进行操作的决定。但是该桶中可能有许多条目。

因此调用equals来标识您感兴趣的条目。由于hashcodeequals不相关(不同的属性)会引入不一致。

假设你有这个:

  EntryA (hashCode = 42, id = 2)
  EntryB (hashCode = 44, id = 2)

根据equal,这些条目为id;但由于它们有不同的hashcodes,它们将在HashMap中的不同部分中转到不同的存储桶

所以现在你将在Map中有两个相同的条目(根据equals) - 这就是为什么hashcode和equals必须彼此一致