hashcode如何存储值

时间:2018-04-20 04:42:57

标签: java java-8 hashmap

我有一个班级

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

}

请注意,我已从等值和哈希码计算中删除了customerId。 我创建了此方法以将客户对象用作键

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

以下方法遍历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());
    }
}

以下是输出。

customerAddress5
     

================================== ENTRY SET =========== ===============================键 - &gt;客户[customerId = 3,customerName = customerName3,
  customerType = customerType3,customerAddress = customerAddress5]值 - &gt;   customer3 HashCode - &gt; 291012570密钥 - &gt;客户[customerId = 4,   customerName = customerName4,customerType = customerType4,   customerAddress = customerAddress4]值 - &gt; customer4 HashCode - &gt;   291011640密钥 - &gt;客户[customerId = 2,customerName = customerName2,   customerType = customerType2,customerAddress = customerAddress2]值 - &gt;   customer2 HashCode - &gt; 291210360密钥 - &gt;客户[customerId = 1,   customerName = customerName1,customerType = customerType1,   customerAddress = customerAddress1]值 - &gt; customer1 HashCode - &gt;   291211416

     

================================== KEY SET =========== ===============================键 - &gt;客户[customerId = 4,customerName = customerName4,
  customerType = customerType4,customerAddress = customerAddress4]值 - &gt;   customer4 HashCode - &gt; 1611562006密钥 - &gt;客户[customerId = 2,   customerName = customerName2,customerType = customerType2,   customerAddress = customerAddress2]值 - &gt; customer2 HashCode - &gt;   1611562004密钥 - &gt;客户[customerId = 1,customerName = customerName1,   customerType = customerType1,customerAddress = customerAddress1]值 - &gt;   customer1 HashCode - &gt; 1611562003

我对这个hashmap行为有几个问题

  1. 为什么hashmap不受customer4 = new assignment的影响,hashcode如何存储这些。
  2. 如何通过customer3.setCustomerAddress影响hashmap(&#34; customerAddress5&#34;);
  3. 为什么keyset()和entryset方法返回了两个不同的值。
  4. hashmap是否存储实际对象的引用,如果引用则为什么customer4 = new对hashmap没有影响?

3 个答案:

答案 0 :(得分:3)

  

为什么hashmap不受customer4 = new assignment的影响,hashcode如何存储这些。

您正在为customer4变量分配新对象,您不会更改对象本身。 Map保存对旧对象的引用,并且不知道您已更改customer4

  

如何通过customer3.setCustomerAddress(“customerAddress5”);

影响hashmap

您正在更改对象本身。地图中的customer3和客户都指向同一个对象。

  

为什么keyset()和entryset方法返回了两个不同的值。

永远不要将可变对象作为键。或者至少在放入地图后不要改变它们。地图无法处理此更改,无法重新排序条目。这就是"customerAddres5"的密钥被“遗漏”的原因。

  
    

我可以看到更改反映在entryset()而不是keyset()中,这让我想知道hashmap如何能够用一种方法而不是另一种方法来应对更改。

  

entrySet方法返回带有(key - &gt; value)对的整个集合。您对null != mapKeys的检查在这里是多余的,因为它们都不为空并且它们已经相互连接。

keySet方法仅返回密钥。它还返回4个项目,但您要过滤掉"customerAddress5"条目,因为您正在尝试通过此键获取值。但是,由于您更改了address字段并且地图无法检索此密钥的值,因此该密钥的哈希码已更改。

结论:从不更改关键状态。让它变得一成不变,所以没人能改变它。

  

hashmap是否存储实际对象的引用,如果引用则为什么customer4 = new对hashmap没有影响?

您正在重新分配customer4。再次阅读第一个问题的答案。

答案 1 :(得分:0)

您必须了解的是,您的四个Customer变量中的每一个都只是某个对象的引用。当您致电map.put(customer4, "customer4");时,您说'使用变量customer4引用的对象作为值“customer4”的键。当您使用customer4语句重新分配new时,不会修改对象,而是更改customer4,以便它不再引用该第一个对象。

关于你的第二个问题,customer3同样是对变量的引用。在指定customer3引用new对象后,您将该对象放入HashMap。现在有两个对这个对象的引用;其中一个是customer3,另一个是HashMap中的条目。当您致电setCustomerAddress()时,您现在正在对该对象进行操作,因此可以从这两个参考点看到更改。

至于keyset()和entryset()方法为什么返回differentnet hashCode,在第一个循环中,mapKeys的类型为Entry,而在第二个循环中,{ {1}}类型为map.get(mapKeys),因此它们会自然地生成不同的String

最后,Java中的所有内容都是一个参考。当您hashCode customer4进入Map时,您实际上是在引用Object。当您重新分配customer4时,您只是将变量指向另一个Object,但该引用的另一个副本并没有消失。因此,更改变量put不会影响地图中的条目。

答案 2 :(得分:0)

  1. 在这里,您将customer4指向另一个对象。因此,HashMap不会受到影响。对第四个问题的回答是一样的。

  2. 所有这些都是因为您的Customer对象是Mutable。 您可以参考thisthis来了解为什么HashMap键应该是不可变的。

  3. 这是因为您已通过customer3.setCustomerAddress更改了Customer对象。 检索Keyset()时,将返回所有键。但是当您尝试使用该密钥检索该值时,它现在将指向另一个存储桶(请记住您已使用客户地址来计算哈希码)。