Home > Java > javaTutorial > How to modify the value in Hashmap based on key value in Java

How to modify the value in Hashmap based on key value in Java

王林
Release: 2023-05-13 14:25:06
forward
3287 people have browsed it

    Modify the value of Hashmap according to the key value

    If there is no key in the original map, it will be created. If there is a key in the original map, the original value will be overwritten with value. The value of

    map.put(key,value);
    Copy after login

    This implementation adds one to the original value (provided there is this key)

    map.put(key,map.get(key)+1);
    Copy after login

    The value corresponding to the key can be obtained as follows, if not, the default value can be returned

    map.getOrDefault(key,value);
    Copy after login

    Can the value be obtained correctly after the key of HashMap is changed?

    A series of key-value pairs stored in HashMap, where the key is a custom type. After putting it into HashMap, we change the attributes of a certain key externally, and then we use this key to take out elements from HashMap. What will HashMap return at this time?

    The answers from several people in our office are inconsistent. Some say it returns null, and some say it can return value normally. But whatever the answer is, there is no solid reason. I thought this question was quite interesting, so I wrote a code test. The result is null. It should be noted that our custom class overrides the hashCode method. I think this result is a bit unexpected, because we know that HashMap stores reference types, and we updated the key outside, which means that the key inside the HashMap is also updated, which means that the hashCode return value of this key will also happen. Variety. At this time, the hashCode of key and HashMap must be the same as the hashCode of the element, and equals will definitely return true, because it is the same object, so why can't it return the correct value?

    Test Case

    There are 2 cases here, one is the Person class, and the other is the Student class. Let’s verify the above point of view (with conclusion):

    • Whether modifying the properties of an object will change its hashcode => Yes

    • Whether the value will be affected by modifying the properties when accessing the HashMap=> ; The value is null

    package tech.luxsun.interview.luxinterviewstarter.collection;
     
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import java.util.HashMap;
     
    /**
     * @author Lux Sun
     * @date 2021/4/22
     */
    public class MapDemo0 {
     
        public static void main(String[] args) {
            HashMap<Object, Object> map = new HashMap<>();
     
            // Person Case
            Person p = new Person("Bob", 12);
            map.put(p, "person");
            System.out.println(p.hashCode());
            System.out.println(map.get(p));
     
            p.setAge(13);
            System.out.println(p.hashCode());
            System.out.println(map.get(p));
     
            // Student Case
            Student stu = new Student("Bob", 12);
            map.put(stu, "student");
            System.out.println(stu.hashCode());
            System.out.println(map.get(stu));
     
            stu.setAge(13);
            System.out.println(stu.hashCode());
            System.out.println(map.get(stu));
        }
    }
     
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    class Person {
        private String name;
        private Integer age;
     
        public int hashCode() {
            return 123456;
        }
    }
     
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    class Student {
        private String name;
        private Integer age;
    }
    Copy after login

    Output result

    123456
    person
    123456
    person
    71154
    student
    71213
    null

    Source code

    hashCode source code

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $age = this.getAge();
        int result = result * 59 + ($age == null ? 43 : $age.hashCode());
        Object $name = this.getName();
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }
    Copy after login

    map.get source code

    /**
     * Returns the value to which the specified key is mapped,
     * or {@code null} if this map contains no mapping for the key.
     *
     * <p>More formally, if this map contains a mapping from a key
     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
     * key.equals(k))}, then this method returns {@code v}; otherwise
     * it returns {@code null}.  (There can be at most one such mapping.)
     *
     * <p>A return value of {@code null} does not <i>necessarily</i>
     * indicate that the map contains no mapping for the key; it&#39;s also
     * possible that the map explicitly maps the key to {@code null}.
     * The {@link #containsKey containsKey} operation may be used to
     * distinguish these two cases.
     *
     * @see #put(Object, Object)
     */
    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }
     
     
    /**
     * Computes key.hashCode() and spreads (XORs) higher bits of hash
     * to lower.  Because the table uses power-of-two masking, sets of
     * hashes that vary only in bits above the current mask will
     * always collide. (Among known examples are sets of Float keys
     * holding consecutive whole numbers in small tables.)  So we
     * apply a transform that spreads the impact of higher bits
     * downward. There is a tradeoff between speed, utility, and
     * quality of bit-spreading. Because many common sets of hashes
     * are already reasonably distributed (so don&#39;t benefit from
     * spreading), and because we use trees to handle large sets of
     * collisions in bins, we just XOR some shifted bits in the
     * cheapest possible way to reduce systematic lossage, as well as
     * to incorporate impact of the highest bits that would otherwise
     * never be used in index calculations because of table bounds.
     */
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
     
    /**
     * Implements Map.get and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }
    Copy after login

    In short

    You can see that a table is obtained first, and this table is actually an array. Then find the value corresponding to key in the table. The criterion for finding is that the hash is equal to the hash of the passed-in parameter, and meets one of the other two conditions: k = e.key, which means they are the same object, or the key of the equal target of the passed-in key. Our problem lies in the hash(key.hashCode()). You can see that HashMap hashes the hashCode of key when storing elements. The obtained hash will eventually be used as the basis for the storage location of the element. Corresponding to our situation: when storing for the first time, the hash function uses key.hashCode as a parameter to get a value, and then stores the element in a certain location based on this value.

    When we fetch the element again, the value of key.hashCode has changed, so the hash function result here has also changed, so when it tries to obtain the storage location of this key, it cannot Get the correct value, resulting in the target element not being found. To return it correctly, it is very simple. Change the hashCode method of the Person class so that its hashCode does not depend on the attribute we want to modify. However, this must not be done in actual development. We always hope that when the attributes of the two objects are different, Different hashCode values ​​can be returned when they are exactly the same.

    So the conclusion is that after placing the object in a HashMap, do not modify the attributes of the key unless you override the hashCode method of the entity class which is not subject to attribute restrictions.

    The above is the detailed content of How to modify the value in Hashmap based on key value in Java. For more information, please follow other related articles on the PHP Chinese website!

    Related labels:
    source:yisu.com
    Statement of this Website
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
    Popular Tutorials
    More>
    Latest Downloads
    More>
    Web Effects
    Website Source Code
    Website Materials
    Front End Template