6

Mac OS 上の JDK 8。HashMap.java の次のコードを参照してください。

    public Set<K> keySet() {
        Set<K> ks = keySet;
        if (ks == null) {
            ks = new KeySet();
            keySet = ks;
        }
        return ks;
    }

返された ks への変更はすべて keySet に反映されます。これらは常に同じ基になるセットを指しているためです。これが true の場合、次のように記述できます。

    public Set<K> keySet() {
        if (keySet == null) {
            keySet = new KeySet();
        }
        return keySet;
    }

2 つのコード スニペットの動作は同じですか?

もしそうなら、なぜHashMap第 2 バリエーションではなく第 1 バリエーションを使用するのですか?

4

2 に答える 2

-1

@Fransescoによって指摘されているように、ローカル変数は最適化としてのみ保存されます。また、場合によっては、新しいオブジェクトの作成も回避されます。

実装は内部に状態を保存せず、すべての操作の基礎となるハッシュマップで動作し、Java ドキュメントに従ってセットへの変更が期待されます

  • add および addAll は許可されていません (UnsupportedOperationException をスローします)
  • remove、retainAll は、基になるマップを変更することが期待されています

参考のため

   /**
     * Returns a {@link Set} view of the keys contained in this map.
     * The set is backed by the map, so changes to the map are
     * reflected in the set, and vice-versa.  If the map is modified
     * while an iteration over the set is in progress (except through
     * the iterator's own <tt>remove</tt> operation), the results of
     * the iteration are undefined.  The set supports element removal,
     * which removes the corresponding mapping from the map, via the
     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
     * operations.
     *
     * @return a set view of the keys contained in this map
     */
    public Set<K> keySet() {
        Set<K> ks = keySet;
        if (ks == null) {
            ks = new KeySet();
            keySet = ks;
        }
        return ks;
    }

    final class KeySet extends AbstractSet<K> {
        public final int size()                 { return size; }
        public final void clear()               { HashMap.this.clear(); }
        public final Iterator<K> iterator()     { return new KeyIterator(); }
        public final boolean contains(Object o) { return containsKey(o); }
        public final boolean remove(Object key) {
            return removeNode(hash(key), key, null, false, true) != null;
        }
        public final Spliterator<K> spliterator() {
            return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
        }
        public final void forEach(Consumer<? super K> action) {
            Node<K,V>[] tab;
            if (action == null)
                throw new NullPointerException();
            if (size > 0 && (tab = table) != null) {
                int mc = modCount;
                for (int i = 0; i < tab.length; ++i) {
                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
                        action.accept(e.key);
                }
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }
    }

私の知る限り、動作はMacだけでなくすべてのプラットフォームで同じです

于 2020-11-20T06:27:53.740 に答える