2017-05-26 1 views
3

enter image description here // Impossible d'obtenir la valeur d'un objet dans hashmap après avoir surpassé son hashcode // Ceci est la classe d'élément où je produis hascode basé sur le nom de l'élémentImpossible d'obtenir la valeur d'un objet à partir hashmap, même si elle renvoie la même 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); 

        } 

// C'est là que je suis face à la question, si j'Interrogation de la table de hachage pour le même article il me renvoie null, article retourne même la même 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; 
        } 

      } 
+1

Veuillez réduire cela à un [mcve] - il y a un * lot * de code non pertinent. (Ensuite, formatez-le plus lisiblement.) En fin de compte, le problème est l'incohérence entre 'equals' et' hashCode' si ... –

+2

Je ne suis pas sûr si un mcve est réellement nécessaire ici. La seule chose qui manque est quelqu'un prêt à rechercher la question dupliquée appropriée. – GhostCat

+0

@Eugene Mais je ne suis toujours pas convaincu, comme le dit l'explication. Si j'ai deux objets. Un dans le hashmap Warehouse et I; m obtient item2 dans la méthode removeItem. Article item1 = nouvel article ("X box one S", (long) 200, 40000); Item item2 = nouvel article ("X box one S", (long) 200, 40000); , Puis si je génère le hashcode pour le nom, Hashmap va vérifier si le hashcode des deux noms d'éléments est le même droit? Donc, pour item1 et item2, tant que le nom est identique, nous obtenons le même hashcode. si nous comparons id en égaux, cela ne devrait pas être un problème, n'est-ce pas? –

Répondre

5

Votre objet est hashCode utilisé t Il propriété name, mais votre equals utilise la propriété id. Cela viole le contrat. Les objets pour lesquels equals renvoie true doivent avoir le même hashCode.

HashMap utilise à la fois hashCode et equals pour localiser une clé. D'abord, il localise une corbeille dans le HashMap sur la base du hashCode. Ensuite, il passe en revue toutes les entrées dans le bac en utilisant equals pour trouver la clé que vous recherchez. Lorsque hashCode ne correspond pas à equals, deux objets que vous considérez égaux peuvent être mappés à des emplacements différents. L'utilisation de map.contains(key) pour trouver la clé stockée dans Map échouera.

Je pense qu'il serait plus judicieux d'utiliser id comme les critères pour l'égalité, donc j'écrirait:

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

Notez que je equals pour comparer les id s. La comparaison d'objets avec == (Long s dans votre cas) est généralement incorrecte.

En outre, vous pouvez rendre votre méthode equals plus sûre en vérifiant le type de obj avant la coulée à Item et retourner false si le type ne correspond pas.

P.S. en fonction de votre nouveau code, vous avez un autre problème:

Cette condition:

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

sera soit vrai (si num != null) ou jetez un NullPointerException (si num est null). Par conséquent, il ne mettra que item dans le Map s'il est déjà dans le Map. La logique souhaitée n'est pas claire, mais elle ne semble pas correcte.

+0

Merci Eran, voulez-vous donner une explication claire de ce qui se passe? –

+0

Fondamentalement, à droite, à la fois les demandeurs et la méthode 'equals()' de votre choix font un cast non coché à 'Item' - ne passerait pas de révision de code! –

+0

En fait, votre approche fonctionne, mais je ne suis toujours pas capable de comprendre ce que j'ai raté! pourquoi ne pouvons-nous pas générer un hashcode basé sur un champ et cocher égal à l'autre? –

3

La décision de où/quel contient une entrée est prise en fonction de votre hashcode. Mais il pourrait y avoir beaucoup d'entrées dans ce compartiment.

Alors equals est appelé à identifier l'entrée qui vous intéresse. Depuis hashcode et equals sont (propriétés) non adossés qui introduit l'incohérence.

suppose donc que vous avez ceci:

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

Ces entrées sont equal en fonction de id; mais puisqu'ils ont différents hashcodes ils iront à différents seaux dans le HashMap, dans différentes parties.

Alors maintenant vous aurez deux mêmes entrées (selon l'égalité) dans la carte - c'est pourquoi le hashcode et les égales doivent être cohérents entre eux.

+0

Mais je ne suis toujours pas convaincu, comme par l'explication. Si j'ai deux objets. Un dans le hashmap Warehouse et I; m obtient item2 dans la méthode removeItem. Article item1 = nouvel article ("X box one S", (long) 200, 40000); Item item2 = nouvel article ("X box one S", (long) 200, 40000); , Puis si je génère le hashcode pour le nom, Hashmap va vérifier si le hashcode des deux noms d'éléments est le même droit? Donc, pour item1 et item2, tant que le nom est identique, nous obtenons le même hashcode. si nous comparons id en égaux, cela ne devrait pas être un problème, n'est-ce pas? - –

+0

'EntryA (hashCode = nom.hashcode, id = 2) EntréeB (hashCode = nom.hashcode, id = 2)' tant qu'ils sont identiques alors pourquoi cela échoue? Je passe le même nom dans les objets –