简体   繁体   English

hashcode如何存储值

[英]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. 请注意,我已从等于和哈希码计算中删除了customerId。 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. 以下方法遍历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, ================================== ENTRY SET ============== ============================密钥 - >客户[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 customerType = customerType3,customerAddress = customerAddress5]值 - > customer3 HashCode - > 291012570密钥 - >客户[customerId = 4,customerName = customerName4,customerType = customerType4,customerAddress = customerAddress4]值 - > customer4 HashCode - > 291011640密钥 - >客户[ 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, ================================== KEY SET ============== ============================密钥 - >客户[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 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 我对这个hashmap行为有几个问题

  1. why is hashmap not affected by customer4=new assignment, how does hashcode stores these. 为什么hashmap不受customer4 = new assignment的影响,hashcode如何存储这些。
  2. How is hashmap effected by customer3.setCustomerAddress("customerAddress5"); hashMap如何影响customer3.setCustomerAddress(“customerAddress5”);
  3. Why there are two different values returned by keyset() and entryset methods. 为什么keyset()和entryset方法返回了两个不同的值。
  4. Does hashmap store reference for actual objects, if references then why customer4 = new had no impact on hashmap? hashmap是否存储实际对象的引用,如果引用则为什么customer4 = new对hashmap没有影响?

why is hashmap not affected by customer4=new assignment, how does hashcode stores these. 为什么hashmap不受customer4 = new assignment的影响,hashcode如何存储这些。

You are assigning new object to customer4 variable, you do not change the object itself. 您正在为customer4变量分配新对象,您不会更改对象本身。 Map holds reference to the old object and does not know that you have changed customer4 . Map保存对旧对象的引用,并且不知道您已更改customer4

How is hashmap effected by customer3.setCustomerAddress("customerAddress5"); hashMap如何影响customer3.setCustomerAddress(“customerAddress5”);

You are changing the object itself. 您正在更改对象本身。 Both customer3 and customer in the map are pointing to the same object. 地图中的customer3和customer都指向同一个对象。

Why there are two different values returned by keyset() and entryset methods. 为什么keyset()和entryset方法返回了两个不同的值。

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". 这就是"customerAddres5"的密钥被“遗漏”的原因。

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()而不是keyset()中,这让我想知道hashmap如何能够用一种方法而不是另一种方法来应对更改。

entrySet method returns the whole set with (key -> value) pairs. entrySet方法返回带有(key - > value)对的整个集合。 Your check for null != mapKeys is redundant here as they are all not null and they are already connected with each other. 你检查null != mapKeys在这里是多余的,因为它们都不是空的并且它们已经相互连接。

keySet method returns keys only. keySet方法仅返回键。 It also returns 4 items, but you are filtering out entry with "customerAddress5" because you are trying to get value by this key. 它还返回4个项目,但您要过滤掉带有"customerAddress5"条目,因为您试图通过此键获取值。 However, the hashcode has changed for this key since you changed address field and the map is unable to retrieve value for this key. 但是,由于您更改了address字段并且映射无法检索此键的值,因此该密钥的哈希码已更改。

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? hashmap是否存储实际对象的引用,如果引用则为什么customer4 = new对hashmap没有影响?

You are reassigning customer4 . 您正在重新分配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. 您必须了解的是,您的四个Customer变量中的每一个都只是对某个Object的引用。 When you call map.put(customer4, "customer4"); 当你调用map.put(customer4, "customer4"); , you are saying 'use the object referenced by the variable customer4 as the key for a value "customer4"'. ,你要说'使用变量customer4引用的对象作为值“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. 当您使用new语句重新分配customer4时,不会修改Object,而是更改customer4 ,以便它不再引用该第一个Object。

As to your second question, customer3 is likewise a reference to a variable. 至于你的第二个问题, customer3同样是对变量的引用。 After you assign customer3 to reference a new Object, you put that Object in the HashMap . 在指定customer3以引用new Object之后,将该Object放入HashMap Now there are two references to this Object; 现在有两个对这个对象的引用; one of them is customer3 , and the other is the entry in the HashMap . 其中一个是customer3 ,另一个是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. 当您调用setCustomerAddress() ,您现在正在对该Object进行操作,因此从这两个参考点可以看到更改。

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. 至于为什么keyset()和entryset()方法返回不同的hashCode ,在你的第一个循环中, mapKeysEntry类型,而在第二个循环中, map.get(mapKeys)String类型,所以它们自然会产生不同的hashCode

Finally, everything in Java is a reference. 最后,Java中的所有内容都是参考。 When you put customer4 into the Map, you were really putting a reference to an Object. 当您put customer4放入Map时,您实际上是在引用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. 当您重新分配customer4时,您只是将变量指向另一个Object,但该引用的另一个副本并没有消失。 Therefore, changing the variable customer4 did not affect the entry in the Map. 因此,更改变量customer4不会影响Map中的条目。

  1. Here you are pointing customer4 to a different object.So, HashMap won't get affected. 在这里,您将customer4指向另一个对象。因此,HashMap不会受到影响。 Answer to 4th question is same. 对第4个问题的回答是一样的。

  2. All these are because your Customer object is Mutable. 所有这些都是因为您的Customer对象是Mutable。 you can refer this and this to know why HashMap keys should be Immutable. 你可以参考这个这个知道为什么HashMap的键应该是一成不变的。

  3. This is because you have changed the Customer object by customer3.setCustomerAddress. 这是因为您已通过customer3.setCustomerAddress更改了Customer对象。 When you retrieve Keyset() all the keys will be returned. 检索Keyset()时,将返回所有键。 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). 但是当您尝试使用该密钥检索值时,它现在将指向另一个桶(请记住,您已使用客户地址来计算哈希码)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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