< prev index next >

src/java.base/share/classes/java/util/WeakHashMap.java

Print this page
@@ -1,7 +1,7 @@
  /*
-  * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
+  * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this

@@ -41,10 +41,22 @@
   * garbage collector, that is, made finalizable, finalized, and then reclaimed.
   * When a key has been discarded its entry is effectively removed from the map,
   * so this class behaves somewhat differently from other {@code Map}
   * implementations.
   *
+  * <div class="preview-block">
+  *      <div class="preview-comment">
+  *          {@linkplain java.util.Objects#hasIdentity Value objects} can not be used as
+  *          keys in a {@code WeakHashMap}. The {@link #put(Object, Object) put(K, V)}
+  *          method, and all methods that associate a value with a key, throw {@link
+  *          IdentityException} if the key is a value object.
+  *          The {@link WeakHashMap#WeakHashMap(Map)} constructor and the {@link
+  *          #putAll(Map)} method also throw {@code IdentityException} if invoked with
+  *          a {@code Map} containing a key that is a value object.
+  *      </div>
+  * </div>
+  *
   * <p> Both null values and the null key are supported. This class has
   * performance characteristics similar to those of the {@code HashMap}
   * class, and has the same efficiency parameters of <em>initial capacity</em>
   * and <em>load factor</em>.
   *

@@ -85,18 +97,18 @@
   * <p> Each key object in a {@code WeakHashMap} is stored indirectly as
   * the referent of a weak reference.  Therefore a key will automatically be
   * removed only after the weak references to it, both inside and outside of the
   * map, have been cleared by the garbage collector.
   *
-  * <p> <strong>Implementation note:</strong> The value objects in a
+  * <p> <strong>Implementation note:</strong> The values in a
   * {@code WeakHashMap} are held by ordinary strong references.  Thus care
-  * should be taken to ensure that value objects do not strongly refer to their
+  * should be taken to ensure that values do not strongly refer to their
   * own keys, either directly or indirectly, since that will prevent the keys
-  * from being discarded.  Note that a value object may refer indirectly to its
-  * key via the {@code WeakHashMap} itself; that is, a value object may
-  * strongly refer to some other key object whose associated value object, in
-  * turn, strongly refers to the key of the first value object.  If the values
+  * from being discarded.  Note that a value may refer indirectly to its
+  * key via the {@code WeakHashMap} itself; that is, a value may
+  * strongly refer to some other key object whose associated value, in
+  * turn, strongly refers to the key of the first value.  If the values
   * in the map do not rely on the map holding strong references to them, one way
   * to deal with this is to wrap values themselves within
   * {@code WeakReferences} before
   * inserting, as in: {@code m.put(key, new WeakReference(value))},
   * and then unwrapping upon each {@code get}.

@@ -252,10 +264,12 @@
       * load factor (0.75) and an initial capacity sufficient to hold the
       * mappings in the specified map.
       *
       * @param   m the map whose mappings are to be placed in this map
       * @throws  NullPointerException if the specified map is null
+      * @throws  IdentityException if any of the keys in the specified map
+      *          is a value object
       * @since   1.3
       */
      @SuppressWarnings("this-escape")
      public WeakHashMap(Map<? extends K, ? extends V> m) {
          this(Math.max((int) Math.ceil(m.size() / (double)DEFAULT_LOAD_FACTOR),

@@ -286,10 +300,12 @@
      }
  
      /**
       * Checks for equality of non-null reference x and possibly-null y.  By
       * default uses Object.equals.
+      * The key may be a value object, but it will never be equal to the referent
+      * so does not need a separate Objects.hasIdentity check.
       */
      private boolean matchesKey(Entry<K,V> e, Object key) {
          // check if the given entry refers to the given key without
          // keeping a strong reference to the entry's referent
          if (e.refersTo(key)) return true;

@@ -454,13 +470,16 @@
       * @param value value to be associated with the specified key.
       * @return the previous value associated with {@code key}, or
       *         {@code null} if there was no mapping for {@code key}.
       *         (A {@code null} return can also indicate that the map
       *         previously associated {@code null} with {@code key}.)
+      * @throws IdentityException if {@code key} is a {@link
+      *         java.util.Objects#hasIdentity(Object) value object}
       */
      public V put(@jdk.internal.RequiresIdentity K key, V value) {
          Object k = maskNull(key);
+         Objects.requireIdentity(k);
          int h = hash(k);
          Entry<K,V>[] tab = getTable();
          int i = indexFor(h, tab.length);
  
          for (Entry<K,V> e = tab[i]; e != null; e = e.next) {

@@ -544,12 +563,19 @@
      /**
       * Copies all of the mappings from the specified map to this map.
       * These mappings will replace any mappings that this map had for any
       * of the keys currently in the specified map.
       *
+      * @apiNote If the specified map contains keys that are
+      * {@linkplain java.util.Objects#hasIdentity value objects},
+      * an {@linkplain IdentityException} is thrown when the first value object
+      * key is encountered. Zero or more mappings may have already been copied to
+      * this map.
+      *
       * @param m mappings to be stored in this map.
       * @throws  NullPointerException if the specified map is null.
+      * @throws  IdentityException if any of the {@code keys} is a value object
       */
      public void putAll(Map<? extends K, ? extends V> m) {
          int numKeysToBeAdded = m.size();
          if (numKeysToBeAdded == 0)
              return;
< prev index next >