Path: blob/master/src/java.management/share/classes/com/sun/jmx/mbeanserver/WeakIdentityHashMap.java
41161 views
/*1* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.jmx.mbeanserver;2627import static com.sun.jmx.mbeanserver.Util.*;2829import java.lang.ref.Reference;30import java.lang.ref.ReferenceQueue;31import java.lang.ref.WeakReference;3233import java.util.Map;343536/**37* <p>A map where keys are compared using identity comparison (like38* IdentityHashMap) but where the presence of an object as a key in39* the map does not prevent it being garbage collected (like40* WeakHashMap). This class does not implement the Map interface41* because it is difficult to ensure correct semantics for iterators42* over the entrySet().</p>43*44* <p>Because we do not implement Map, we do not copy the questionable45* interface where you can call get(k) or remove(k) for any type of k,46* which of course can only have an effect if k is of type K.</p>47*48* <p>This map does not support null keys.</p>49*/50/*51* The approach52* is to wrap each key in a WeakReference and use the wrapped value as53* a key in an ordinary HashMap. The WeakReference has to be a54* subclass IdentityWeakReference (IWR) where two IWRs are equal if55* they refer to the same object. This enables us to find the entry56* again.57*/58class WeakIdentityHashMap<K, V> {59private WeakIdentityHashMap() {}6061static <K, V> WeakIdentityHashMap<K, V> make() {62return new WeakIdentityHashMap<K, V>();63}6465V get(K key) {66expunge();67WeakReference<K> keyref = makeReference(key);68return map.get(keyref);69}7071public V put(K key, V value) {72expunge();73if (key == null)74throw new IllegalArgumentException("Null key");75WeakReference<K> keyref = makeReference(key, refQueue);76return map.put(keyref, value);77}7879public V remove(K key) {80expunge();81WeakReference<K> keyref = makeReference(key);82return map.remove(keyref);83}8485private void expunge() {86Reference<? extends K> ref;87while ((ref = refQueue.poll()) != null)88map.remove(ref);89}9091private WeakReference<K> makeReference(K referent) {92return new IdentityWeakReference<K>(referent);93}9495private WeakReference<K> makeReference(K referent, ReferenceQueue<K> q) {96return new IdentityWeakReference<K>(referent, q);97}9899/**100* WeakReference where equals and hashCode are based on the101* referent. More precisely, two objects are equal if they are102* identical or if they both have the same non-null referent. The103* hashCode is the value the original referent had. Even if the104* referent is cleared, the hashCode remains. Thus, objects of105* this class can be used as keys in hash-based maps and sets.106*/107private static class IdentityWeakReference<T> extends WeakReference<T> {108IdentityWeakReference(T o) {109this(o, null);110}111112IdentityWeakReference(T o, ReferenceQueue<T> q) {113super(o, q);114this.hashCode = (o == null) ? 0 : System.identityHashCode(o);115}116117public boolean equals(Object o) {118if (this == o)119return true;120if (!(o instanceof IdentityWeakReference<?>))121return false;122@SuppressWarnings("unchecked")123IdentityWeakReference<T> wr = (IdentityWeakReference<T>) o;124T got = get();125return got != null && wr.refersTo(got);126}127128public int hashCode() {129return hashCode;130}131132private final int hashCode;133}134135private Map<WeakReference<K>, V> map = newMap();136private ReferenceQueue<K> refQueue = new ReferenceQueue<K>();137}138139140