java - 哈希码如何存储值

标签 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 ========================================== 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

我有几个关于这个 hashmap 行为的问题

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

最佳答案

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

您正在将新对象分配给 customer4 变量,您没有更改对象本身。 Map 保留对旧对象的引用,并且不知道您已更改 customer4

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

您正在更改对象本身。 map 中的 customer3 和 customer 都指向同一个对象。

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

切勿将可变对象作为键。或者至少在放入 map 后不要更改它们。 map 无法处理此更改且无法重新排序条目。这就是为什么带有 "customerAddres5" 的 key 被“遗漏”了。

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

keySet 方法只返回键。它还返回 4 个项目,但您正在过滤掉带有 "customerAddress5" 的条目,因为您正试图通过此键获取值。但是,自从您更改 address 字段后,此键的哈希码已更改,并且 map 无法检索此键的值。

结论:永远不要改变按键状态。使其不可变,这样任何人都无法更改它。

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

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

关于java - 哈希码如何存储值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49934119/

相关文章:

java - Map.keySet() 读取序列?

java - 在 Spring mvc 中使用 html 文件发送 dto

java - 向 TextField 添加提示

java - 如何将整数流过滤到列表中?

jquery - 如何在 javascript 中构建哈希并将其发布到服务器

java - 使用线程对象作为 HashMap 中的键

java - 存储用户创建的帐户的用户/密码?

java - 在 Neo4j 中使用 cypher 加速关系和节点创建

java - 如何在 Eclipse 中的类型上启用 JSR308 空注释?

java - jdk8 中本地日期的 EpochSeconds