/* * Copyright 2015 Ben Manes. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.benmanes.caffeine.cache; import static java.util.Objects.requireNonNull; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * Static utility methods and classes pertaining to weak and soft references. * * @author ben.manes@gmail.com (Ben Manes) */ @SuppressWarnings("PMD.MissingStaticMethodInNonInstantiatableClass") final class References { private References() {} /** A weak or soft reference that includes the entry's key reference. */ interface InternalReference<E> { /** * Returns this reference object's referent. If this reference object has been cleared, either * by the program or by the garbage collector, then this method returns {@code null}. * * @return The object to which this reference refers, or {@code null} if this reference object * has been cleared */ @CheckForNull E get(); /** * Returns the key that is associated to the cache entry holding this reference. If the cache * holds keys strongly, this is that key instance. Otherwise the cache holds keys weakly and the * {@link WeakKeyReference} is returned. * * @return the key that is associated to the cached entry */ @Nonnull Object getKeyReference(); /** * Returns {@code true} if the arguments is an {@linkplain InternalReference} that holds the * same element. A weakly or softly held element is compared using identity equality. * * @param object the reference object with which to compare * @return {@code true} if this object is the same as the argument; {@code false} otherwise */ default boolean referenceEquals(@Nullable Object object) { if (object == this) { return true; } else if (object instanceof InternalReference<?>) { InternalReference<?> referent = (InternalReference<?>) object; return (get() == referent.get()); } return false; } } /** * A short-lived adapter used for looking up an entry in the cache where the keys are weakly held. * This {@linkplain InternalReference} implementation is not suitable for storing in the cache as * the key is strongly held. */ static final class LookupKeyReference<E> implements InternalReference<E> { private final int hashCode; private final E e; public LookupKeyReference(@Nonnull E e) { this.hashCode = System.identityHashCode(e); this.e = requireNonNull(e); } @Override public E get() { return e; } @Override public Object getKeyReference() { return this; } @Override public boolean equals(Object object) { return referenceEquals(object); } @Override public int hashCode() { return hashCode; } } /** * The key in a cache that holds keys weakly. This class retains the key's identity hash code in * the advent that the key is reclaimed so that the entry can be removed from the cache in * constant time. */ static class WeakKeyReference<K> extends WeakReference<K> implements InternalReference<K> { private final int hashCode; public WeakKeyReference(@Nullable K key, @Nullable ReferenceQueue<K> queue) { super(key, queue); hashCode = System.identityHashCode(key); } @Override public Object getKeyReference() { return this; } @Override public boolean equals(Object object) { return referenceEquals(object); } @Override public int hashCode() { return hashCode; } } /** * The value in a cache that holds values weakly. This class retains a reference to the key in * the advent that the value is reclaimed so that the entry can be removed from the cache in * constant time. */ static final class WeakValueReference<V> extends WeakReference<V> implements InternalReference<V> { private final Object keyReference; public WeakValueReference(@Nonnull Object keyReference, @Nullable V value, @Nullable ReferenceQueue<V> queue) { super(value, queue); this.keyReference = keyReference; } @Override public Object getKeyReference() { return keyReference; } @Override public boolean equals(Object object) { return referenceEquals(object); } @Override @SuppressWarnings("PMD.UselessOverridingMethod") public int hashCode() { return super.hashCode(); } } /** * The value in a cache that holds values softly. This class retains a reference to the key in * the advent that the value is reclaimed so that the entry can be removed from the cache in * constant time. */ static final class SoftValueReference<V> extends SoftReference<V> implements InternalReference<V> { private final Object keyReference; public SoftValueReference(@Nonnull Object keyReference, @Nullable V value, @Nullable ReferenceQueue<V> queue) { super(value, queue); this.keyReference = keyReference; } @Override public Object getKeyReference() { return keyReference; } @Override public boolean equals(Object object) { return referenceEquals(object); } @Override @SuppressWarnings("PMD.UselessOverridingMethod") public int hashCode() { return super.hashCode(); } } }