ホームページ > Java > &#&チュートリアル > Javaのキー値に基づいてハッシュマップの値を変更する方法

Javaのキー値に基づいてハッシュマップの値を変更する方法

王林
リリース: 2023-05-13 14:25:06
転載
3291 人が閲覧しました

    キーの値に応じてハッシュマップの値を変更します

    元のマップにキーがない場合は作成されます。元のマップのキーの場合、元の値は value で上書きされます。

    map.put(key,value);
    ログイン後にコピー

    の値は、元の値に 1 を加算します (このキーがある場合)

    map.put(key,map.get(key)+1);
    ログイン後にコピー

    対応する値キーへの値は次のように取得できますが、そうでない場合はデフォルト値を返すことができます

    map.getOrDefault(key,value);
    ログイン後にコピー

    HashMapのキーを変更した後、値は正しく取得できますか?

    HashMap に格納される一連のキーと値のペア。キーはカスタム タイプです。 HashMapに入れた後、外部からあるキーの属性を変更し、そのキーを使ってHashMapから要素を取り出すのですが、このときHashMapは何を返すのでしょうか?

    社内の数人の回答はバラバラで、nullが返されるという人もいれば、普通に値が返せるという人もいます。しかし、答えが何であれ、明確な理由はありません。この質問は非常に興味深いと思ったので、コードテストを書きました。結果はヌルです。カスタム クラスは hashCode メソッドをオーバーライドすることに注意してください。この結果は少し予想外だと思います。HashMap には参照型が格納されていることがわかっていて、外側のキーを更新しました。つまり、HashMap 内のキーも更新され、このキーの hashCode 戻り値も更新されることになります。 。 バラエティ。このとき、keyとHashMapのhashCodeは要素のhashCodeと同じである必要があり、同じオブジェクトなのでequalsは必ずtrueを返すはずですが、なぜ正しい値を返せないのでしょうか?

    テスト ケース

    ここには 2 つのケースがあり、1 つは person クラス、もう 1 つは Student クラスです。上記の観点を (結論とともに) 検証してみましょう:

    • オブジェクトのプロパティを変更するとハッシュコードが変更されるかどうか => はい

    • 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
    学生
    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;
    }
    ログイン後にコピー

    つまり、

    最初にテーブルが取得され、このテーブルが実際には配列であることがわかります。次に、テーブル内のキーに対応する値を見つけます。検索の基準は、ハッシュが渡されたパラメータのハッシュと等しく、他の 2 つの条件のいずれかを満たしていることです: k = e.key。これは、それらが同じオブジェクトであるか、等しいターゲットのキーであることを意味します。渡されたキーの。問題は hash(key.hashCode()) にあります。HashMap が要素を格納するときにキーの hashCode をハッシュしていることがわかります。取得されたハッシュは、最終的に要素の保存場所の基礎として使用されます。今回の状況に対応すると、初めて保存するとき、ハッシュ関数は key.hashCode をパラメーターとして使用して値を取得し、この値に基づいて要素を特定の場所に保存します。

    要素を再度取得すると、key.hashCode の値が変更されているため、ここでのハッシュ関数の結果も変更されているため、このキーの格納場所を取得しようとすると、正しい値を取得できません。値が不足しているため、ターゲット要素が見つかりません。正しく返すには、非常に簡単です。変更したい属性にその hashCode が依存しないように、Person クラスの hashCode メソッドを変更します。ただし、これは実際の開発では行うべきではありません。 2 つのオブジェクトの属性は異なりますが、まったく同じである場合は、異なる hashCode 値が返されることがあります。

    結論としては、オブジェクトを HashMap に配置した後は、属性の制限を受けないエンティティ クラスの hashCode メソッドをオーバーライドしない限り、キーの属性を変更しないでください。

    以上がJavaのキー値に基づいてハッシュマップの値を変更する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    関連ラベル:
    ソース:yisu.com
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート