2017-05-26 51 views
3

enter image description here //無法在覆蓋hashcode後獲取哈希映射中對象的值 //這是我生成基於​​代碼的項目類在項目名稱無法從哈希表中獲取對象的值,即使它返回相同的哈希碼

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它返回我空同一個項目,項目甚至返回相同的哈希碼

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

      } 
+1

請把它降低到[mcve] - 那裏有很多不相關的代碼。 (然後格式化它更容易。)最終,問題是'equals'和'hashCode'之間的不一致... –

+2

我不確定這裏是否真的需要mcve。唯一缺少的是有人願意查找適當的重複問題。 – GhostCat

+0

@Eugene但我仍然不相信,因爲每個解釋。如果我有兩件物品。一個在Warehouse hashmap和I中; m在removeItem方法中獲取item2。商品item1 =新商品(「X box one S」,(長)200,40000);項目item2 =新項目(「X box one S」,(長)200,40000); ,然後如果我生成名稱的散列碼,Hashmap將檢查兩個項目名稱的散列碼是否相同?所以對於item1和item2,只要名稱相同,我們就可以得到相同的哈希碼。如果我們將平等中的id比較,那不應該是個問題吧? –

回答

5

你的對象的hashCode使用t他name財產,但您的equals使用id財產。這違反了合同。 equals返回true的對象必須具有相同的hashCode

HashMap同時使用hashCodeequals來定位密鑰。首先,它根據hashCode根據HashMap找到一個垃圾箱。然後使用equals查看箱中的所有條目以找到您要查找的密鑰。當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)進行比較通常是錯誤的。

此外,您可能想使你的equals方法更安全通過檢查obj類型強制轉換到Item之前,並返回false如果類型不匹配。

P.S.基於新的代碼,你有另外一個問題:

這種情況:

if(null!= num||num!=0 ) 

要麼是真(如果num != null)或拋出一個NullPointerException(如果numnull)。

因此,如果它已經在Map中,那麼它只會將item放在Map中。目前尚不清楚理想的邏輯是什麼,但它看起來不正確。

+0

謝謝艾蘭,請你給出一個清晰的解釋發生了什麼! –

+0

基本上,buth asker和你的'equals()'方法使一個未檢查的轉換爲'Item' - 不會通過任何代碼檢查! –

+0

其實你的方法有效,但我仍然無法理解我錯過了什麼!爲什麼我們不能生成基於一個字段的哈希碼並檢查其他的等於? –

3

決定哪個/哪個存儲一些條目將根據您的hashcode獲取。但是在該存儲桶中可能有多個條目。

所以equals被稱爲識別輸入你感興趣的。因爲hashcodeequals是不相關的(不同的屬性),介紹的不一致。

因此,假設你有這樣的:

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

這些條目equal基於id;但由於他們有不同的hashcodes他們會在不同的部分在HashMap中去不同的桶

所以現在你將在Map中有兩個相同的條目(根據等於) - 這就是爲什麼hashcode和equals必須是彼此一致

+0

但我仍然不相信,因爲每個解釋。如果我有兩件物品。一個在Warehouse hashmap和I中; m在removeItem方法中獲取item2。商品item1 =新商品(「X box one S」,(長)200,40000);項目item2 =新項目(「X box one S」,(長)200,40000); ,然後如果我生成名稱的散列碼,Hashmap將檢查兩個項目名稱的散列碼是否相同?所以對於item1和item2,只要名稱相同,我們就可以得到相同的哈希碼。如果我們將平等中的id比較,那不應該是個問題吧? - –

+0

EntryA(hashCode = name.hashcode,id = 2) EntryB(hashCode = name.hashcode,id = 2)'只要它們相同,那麼它爲什麼會失敗?我在對象中傳遞了相同的名稱 –