简体   繁体   中英

How hashcode stores values

I have a class

public class Customer {

    private int customerId;
    private String customerName;
    private String customerType;
    private String customerAddress;

    public Customer(int customerId, String customerName, String customerType, String customerAddress) {
        super();
        this.customerId = customerId;
        this.customerName = customerName;
        this.customerType = customerType;
        this.customerAddress = customerAddress;
    }

    public int getCustomerId() {
        return customerId;
    }

    public void setCustomerId(int customerId) {
        this.customerId = customerId;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public String getCustomerType() {
        return customerType;
    }

    public void setCustomerType(String customerType) {
        this.customerType = customerType;
    }

    public String getCustomerAddress() {
        return customerAddress;
    }

    public void setCustomerAddress(String customerAddress) {
        this.customerAddress = customerAddress;
    }

    @Override
    public String toString() {
        return "Customer [customerId=" + customerId + ", customerName=" + customerName + ", customerType="
                + customerType + ", customerAddress=" + customerAddress + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((customerAddress == null) ? 0 : customerAddress.hashCode());
        result = prime * result + ((customerName == null) ? 0 : customerName.hashCode());
        result = prime * result + ((customerType == null) ? 0 : customerType.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Customer other = (Customer) obj;
        if (customerAddress == null) {
            if (other.customerAddress != null)
                return false;
        } else if (!customerAddress.equals(other.customerAddress))
            return false;
        if (customerName == null) {
            if (other.customerName != null)
                return false;
        } else if (!customerName.equals(other.customerName))
            return false;
        if (customerType == null) {
            if (other.customerType != null)
                return false;
        } else if (!customerType.equals(other.customerType))
            return false;
        return true;
    }

}

Notice that I have removed the customerId from equal and hashcode calculation. I Created this method to using customer object as a key

public static Map<Customer, String> testKeysWithObject(){
    Map<Customer, String> map = new HashMap<>();

    Customer customer1 = new Customer(1, "customerName1", "customerType1", "customerAddress1");
    Customer customer2 = new Customer(2, "customerName2", "customerType2", "customerAddress2");
    Customer customer3 = new Customer(3, "customerName3", "customerType3", "customerAddress3");
    Customer customer4 = new Customer(4, "customerName4", "customerType4", "customerAddress4");


    map.put(customer1, "customer1");
    map.put(customer2, "customer2");
    map.put(customer3, "customer3");
    map.put(customer4, "customer4");

    customer4 = new Customer(5, "customerName5", "customerType5", "customerAddress5");

    customer3.setCustomerAddress("customerAddress5");
    System.out.println(customer4.getCustomerAddress());
    return map;
}

And the below method to traverse the Hashmap.

public static void displayMap(Map<Customer, String> map) {
    System.out.println("==================================  ENTRY SET  ==========================================");
    for (Entry<Customer, String> mapKeys : map.entrySet()) {
        if(null != mapKeys)
            System.out.println("Key -> " + mapKeys.getKey() + " Value -> " + mapKeys.getValue()+ " HashCode -> " + mapKeys.hashCode());
    }
    System.out.println();
    System.out.println("==================================  KEY SET  ==========================================");
    for (Customer mapKeys : map.keySet()) {
        if(null != map.get(mapKeys))
            System.out.println("Key -> " + mapKeys + " Value -> " + map.get(mapKeys) + " HashCode -> " + map.get(mapKeys).hashCode());
    }
}

and below is the output.

 customerAddress5 

================================== ENTRY SET ========================================== Key -> Customer [customerId=3, customerName=customerName3,
customerType=customerType3, customerAddress=customerAddress5] Value -> customer3 HashCode -> 291012570 Key -> Customer [customerId=4, customerName=customerName4, customerType=customerType4, customerAddress=customerAddress4] Value -> customer4 HashCode -> 291011640 Key -> Customer [customerId=2, customerName=customerName2, customerType=customerType2, customerAddress=customerAddress2] Value -> customer2 HashCode -> 291210360 Key -> Customer [customerId=1, customerName=customerName1, customerType=customerType1, customerAddress=customerAddress1] Value -> customer1 HashCode -> 291211416

================================== KEY SET ========================================== Key -> Customer [customerId=4, customerName=customerName4,
customerType=customerType4, customerAddress=customerAddress4] Value -> customer4 HashCode -> 1611562006 Key -> Customer [customerId=2, customerName=customerName2, customerType=customerType2, customerAddress=customerAddress2] Value -> customer2 HashCode -> 1611562004 Key -> Customer [customerId=1, customerName=customerName1, customerType=customerType1, customerAddress=customerAddress1] Value -> customer1 HashCode -> 1611562003

I have a couple of question on this hashmap behavior

  1. why is hashmap not affected by customer4=new assignment, how does hashcode stores these.
  2. How is hashmap effected by customer3.setCustomerAddress("customerAddress5");
  3. Why there are two different values returned by keyset() and entryset methods.
  4. Does hashmap store reference for actual objects, if references then why customer4 = new had no impact on hashmap?

why is hashmap not affected by customer4=new assignment, how does hashcode stores these.

You are assigning new object to customer4 variable, you do not change the object itself. Map holds reference to the old object and does not know that you have changed customer4 .

How is hashmap effected by customer3.setCustomerAddress("customerAddress5");

You are changing the object itself. Both customer3 and customer in the map are pointing to the same object.

Why there are two different values returned by keyset() and entryset methods.

Never put mutable objects as keys. Or at least do not change them after putting into map. The map is unable to handle this change and unable to reorder entries. That is why the key with "customerAddres5" is "missed".

As I can see changes are reflected in entryset() and not in keyset() that makes me wonder how is hashmap able to cop up with the change with one method and not with another.

entrySet method returns the whole set with (key -> value) pairs. Your check for null != mapKeys is redundant here as they are all not null and they are already connected with each other.

keySet method returns keys only. It also returns 4 items, but you are filtering out entry with "customerAddress5" because you are trying to get value by this key. However, the hashcode has changed for this key since you changed address field and the map is unable to retrieve value for this key.

Conclusion: never change key state. Make it immutable so nobody can change it.

Does hashmap store reference for actual objects, if references then why customer4 = new had no impact on hashmap?

You are reassigning customer4 . Read answer for the first question again.

What you have to understand is that each of your four Customer variables is simply a reference to an Object somewhere. When you call map.put(customer4, "customer4"); , you are saying 'use the object referenced by the variable customer4 as the key for a value "customer4"'. When you reassign customer4 with the new statement, the Object is not modified, but rather customer4 is changed so that it no longer references that first Object.

As to your second question, customer3 is likewise a reference to a variable. After you assign customer3 to reference a new Object, you put that Object in the HashMap . Now there are two references to this Object; one of them is customer3 , and the other is the entry in the HashMap . When you call setCustomerAddress() , you are now operating on that Object, and so the change will be visible from both of those reference points.

As to why the keyset() and entryset() methods return differnet hashCode s, in your first loop, mapKeys is of type Entry , whereas in the second loop, map.get(mapKeys) is of type String , so they will naturally produce different hashCode s.

Finally, everything in Java is a reference. When you put customer4 into the Map, you were really putting a reference to an Object. When you reassigned customer4, you were simply pointing a variable towards another Object, but the other copy of the reference did not go away. Therefore, changing the variable customer4 did not affect the entry in the Map.

  1. Here you are pointing customer4 to a different object.So, HashMap won't get affected. Answer to 4th question is same.

  2. All these are because your Customer object is Mutable. you can refer this and this to know why HashMap keys should be Immutable.

  3. This is because you have changed the Customer object by customer3.setCustomerAddress. When you retrieve Keyset() all the keys will be returned. But when you try to retrieve the value using that key then it will now point to a different bucket(Remember you have used customer address to calculate hashcode).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM