搜尋
首頁Javajava教程Java怎麼根據key值修改Hashmap中的value值

Java怎麼根據key值修改Hashmap中的value值

May 13, 2023 pm 02:25 PM
javahashmapkey

    根據key值修改Hashmap的value值

    #如果原來map中沒有key,會創建,如果原來有key,會使用value 覆寫原來的值

    map.put(key,value);

    這個實作對原值加一(前提是有這個key)

    map.put(key,map.get(key)+1);

    以下可以取得key對應的value,如果沒有可以回傳預設的value

    map.getOrDefault(key,value);

    HashMap的key更改後能否正確取得value?

    在HashMap 中存放的一系列鍵值對,其中鍵為某個我們自訂的類型。放入 HashMap 後,我們在外部把某一個 key 的屬性進行更改,然後我們再用這個 key 從 HashMap 裡取出元素,這時候 HashMap 會回傳什麼?

    我們辦公室幾個人答案都不一致,有的說返回null,有的說能正常返回value。但不論答案是什麼都沒有確切的理由。我覺得這個問題蠻有趣的,就寫了程式碼測試。結果是回傳null。需要說明的是我們自訂的類別重寫了 hashCode 方法。我想這個結果還是有點意外的,因為我們知道HashMap 存放的是引用類型,我們在外面把key 更新了,那也就是說HashMap 裡面的key 也更新了,也就是這個key 的hashCode 回傳值也會發生變化。這時候 key 的 hashCode 和 HashMap 對於元素的 hashCode 肯定一樣,equals也肯定回傳true,因為本來就是同一個對象,那為什麼不能回傳正確的值呢?

    測試案例

    這裡有2 個案例,一個是Person 類,還有一個是Student 類,我們來驗證下以上的觀點(附帶結論):

    • 修改了物件屬性是否會改變它的hashcode => 是的

    • 在HashMap 裡訪問的時候是否會受到修改屬性影響取值=> ; 取值為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;
    }

    輸出結果

    #123456
    person
    123456
    person
    71154
    student
    71213
    null

    原始碼

    hashCode 原始碼

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

    map.get 原始碼

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

    總之

    可以看到先取得了一個table,這個table其實是個陣列。然後在table裡面找對應 key 的value。找的標準就是hash等於傳入參數的hash, 並且滿足另外兩個條件之一:k = e.key,也就是說他們是同一個對象,或是傳入的 key 的equal目標的 key 。我們的問題出在那個hash(key.hashCode()),可以看到 HashMap 在儲存元素時是把 key 的 hashCode 再做了一次hash。得到的hash將最終作為元素儲存位置的依據。對應到我們的情況:第一次儲存時,hash函數採用key.hashCode作為參數得到了一個值,然後根據這個值把元素存到了某個位置。

    當我們再去取元素的時候,key.hashCode的值已經出現了變化,所以這裡的hash函數結果也發生了變化,所以當它嘗試去獲得這個key 的存儲位置時就不能得到正確的值,導致最終找不到目標元素。要想能正確返回,很簡單,把Person類別的hashCode 方法改一下,讓它的hashCode 不依賴我們要修改的屬性,但實際開發中肯定不能這麼幹,我們總是希望當兩個物件的屬性不完全相同時能傳回不同的hashCode 值。

    所以結論就是當把物件放到 HashMap 後,不要去修改 key 的屬性,除非你重寫了該實體類別的 hashCode 方法不受屬性限制。

    以上是Java怎麼根據key值修改Hashmap中的value值的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述
    本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    AI Hentai Generator

    AI Hentai Generator

    免費產生 AI 無盡。

    熱門文章

    R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
    1 個月前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.最佳圖形設置
    1 個月前By尊渡假赌尊渡假赌尊渡假赌
    威爾R.E.P.O.有交叉遊戲嗎?
    1 個月前By尊渡假赌尊渡假赌尊渡假赌

    熱工具

    PhpStorm Mac 版本

    PhpStorm Mac 版本

    最新(2018.2.1 )專業的PHP整合開發工具

    SublimeText3 Linux新版

    SublimeText3 Linux新版

    SublimeText3 Linux最新版

    VSCode Windows 64位元 下載

    VSCode Windows 64位元 下載

    微軟推出的免費、功能強大的一款IDE編輯器

    ZendStudio 13.5.1 Mac

    ZendStudio 13.5.1 Mac

    強大的PHP整合開發環境

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器