Class ClassValueMap<V>

java.lang.Object
java.util.AbstractMap<Class<?>,V>
com.cedarsoftware.util.ClassValueMap<V>
Type Parameters:
V - the type of mapped values
All Implemented Interfaces:
ConcurrentMap<Class<?>,V>, Map<Class<?>,V>

public class ClassValueMap<V> extends AbstractMap<Class<?>,V> implements ConcurrentMap<Class<?>,V>
A Map implementation keyed on Class objects that leverages a ClassValue cache for extremely fast lookups. This specialized collection is designed for scenarios where you frequently need to retrieve values associated with Class keys.

Performance Advantages

ClassValueMap provides significantly faster get() operations compared to standard Map implementations:

  • 2-10x faster than HashMap for key lookups
  • 3-15x faster than ConcurrentHashMap for concurrent access patterns
  • The performance advantage increases with contention (multiple threads)
  • Most significant when looking up the same class keys repeatedly

Typed fast path: getByClass(Class)

The standard get(Object) method must accept an Object and perform a runtime instanceof Class guard before routing to the ClassValue cache (keys that are not Class instances fall through to the backing ConcurrentHashMap). When the caller already knows the key is a Class, getByClass(Class) skips that guard entirely and compiles to a near-direct ClassValue.get(Class) call — a JIT-intrinsified, identity-based per-Class load.

For performance-critical call sites, prefer getByClass(Class). To take advantage of it, hold the field as ClassValueMap<V> (not Map<Class<?>, V>), so the compiler resolves the typed lookup statically.

How It Works

The implementation utilizes Java's ClassValue mechanism, which is specially optimized in the JVM through:

  • Thread-local caching for reduced contention
  • Identity-based lookups (faster than equality checks)
  • Special VM support that connects directly to Class metadata structures
  • Optimized memory layout that can reduce cache misses

Drop-in Replacement

ClassValueMap is designed as a drop-in replacement for existing maps with Class keys:

  • Fully implements the Map and ConcurrentMap interfaces
  • Supports all standard map operations (put, remove, clear, etc.)
  • Handles null keys and null values just like standard map implementations
  • Thread-safe for all operations

Ideal Use Cases

ClassValueMap is ideal for:

  • High read-to-write ratio scenarios (read-mostly workloads)
  • Caches for class-specific handlers, factories, or metadata
  • Performance-critical operations in hot code paths
  • Type registries in frameworks (serializers, converters, validators)
  • Class capability or feature mappings
  • Any system that frequently maps from Class objects to associated data

Trade-offs

The performance benefits come with some trade-offs:

  • Higher memory usage (maintains both a backing map and ClassValue cache)
  • Write operations (put/remove) aren't faster and may be slightly slower
  • Only Class keys benefit from the optimized lookups

Thread Safety

This implementation is thread-safe for all operations and implements ConcurrentMap.

Usage Example


 // Create a registry of class handlers
 ClassValueMap<Handler> handlerRegistry = new ClassValueMap<>();
 handlerRegistry.put(String.class, new StringHandler());
 handlerRegistry.put(Integer.class, new IntegerHandler());
 handlerRegistry.put(List.class, new ListHandler());

 // Fast lookup in a performance-critical context — getByClass skips the
 // instanceof-Class guard that get(Object) must perform.
 public void process(Object obj) {
     Handler handler = handlerRegistry.getByClass(obj.getClass());
     if (handler != null) {
         handler.handle(obj);
     } else {
         // Default handling
     }
 }
 

Important Performance Warning

Wrapping this class with standard collection wrappers like Collections.unmodifiableMap() or Collections.newSetFromMap() will destroy the ClassValue performance benefits. Always use the raw ClassValueMap directly or use the provided unmodifiableView() method if immutability is required. Note that unmodifiableView() returns a Map<Class<?>, V>, which does not expose getByClass(Class) — callers that need the typed fast path should hold the view as a reference to the raw ClassValueMap.

Author:
John DeRegnaucourt ([email protected])
Copyright (c) Cedar Software LLC

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

License

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.
See Also:
  • Constructor Details

    • ClassValueMap

      public ClassValueMap()
      Creates a ClassValueMap
    • ClassValueMap

      public ClassValueMap(Map<? extends Class<?>,? extends V> map)
      Creates a ClassValueMap containing the mappings from the specified map.
      Parameters:
      map - the map whose mappings are to be placed in this map
      Throws:
      NullPointerException - if the specified map is null
  • Method Details

    • get

      public V get(Object key)
      Specified by:
      get in interface Map<Class<?>,V>
      Overrides:
      get in class AbstractMap<Class<?>,V>
    • getByClass

      public V getByClass(Class<?> key)
      Typed-access companion to get(Object) for callers that already hold a Class<?> reference. Bypasses the key.getClass() == Class.class type guard that get(Object) must perform because its Map contract takes Object. Results are identical to get(Object); the only difference is fewer instructions on the hot path.

      Null-safe: a null key returns the current null-key mapping (or null if none), matching the semantics of get(Object) with a null argument.

      Use this method anywhere the caller has a Class<?> in hand — internal caches, type registries, annotation metadata lookups, conversion dispatch tables, etc. The saved work is small per call (a GETFIELD + CMP + branch + a cast the JIT doesn't always elide), but adds up across the millions of calls per second that a library like this sees through its hot paths.

      Parameters:
      key - the class key, or null
      Returns:
      the mapped value, or null if no mapping exists (or if the null key has no mapping, for a null argument)
      See Also:
    • put

      public V put(Class<?> key, V value)
      Specified by:
      put in interface Map<Class<?>,V>
      Overrides:
      put in class AbstractMap<Class<?>,V>
    • remove

      public V remove(Object key)
      Specified by:
      remove in interface Map<Class<?>,V>
      Overrides:
      remove in class AbstractMap<Class<?>,V>
    • containsKey

      public boolean containsKey(Object key)
      Specified by:
      containsKey in interface Map<Class<?>,V>
      Overrides:
      containsKey in class AbstractMap<Class<?>,V>
    • clear

      public void clear()
      Specified by:
      clear in interface Map<Class<?>,V>
      Overrides:
      clear in class AbstractMap<Class<?>,V>
    • size

      public int size()
      Specified by:
      size in interface Map<Class<?>,V>
      Overrides:
      size in class AbstractMap<Class<?>,V>
    • isEmpty

      public boolean isEmpty()
      Specified by:
      isEmpty in interface Map<Class<?>,V>
      Overrides:
      isEmpty in class AbstractMap<Class<?>,V>
    • containsValue

      public boolean containsValue(Object value)
      Specified by:
      containsValue in interface Map<Class<?>,V>
      Overrides:
      containsValue in class AbstractMap<Class<?>,V>
    • forEach

      public void forEach(BiConsumer<? super Class<?>,? super V> action)
      Specified by:
      forEach in interface ConcurrentMap<Class<?>,V>
      Specified by:
      forEach in interface Map<Class<?>,V>
    • entrySet

      public Set<Map.Entry<Class<?>,V>> entrySet()
      Specified by:
      entrySet in interface Map<Class<?>,V>
      Specified by:
      entrySet in class AbstractMap<Class<?>,V>
    • putIfAbsent

      public V putIfAbsent(Class<?> key, V value)
      Specified by:
      putIfAbsent in interface ConcurrentMap<Class<?>,V>
      Specified by:
      putIfAbsent in interface Map<Class<?>,V>
    • computeIfAbsent

      public V computeIfAbsent(Class<?> key, Function<? super Class<?>,? extends V> mappingFunction)

      Overridden to correctly handle null-value mappings. The default ConcurrentMap implementation cannot distinguish between "key absent" and "key maps to null" (both return null from get()), causing the computed value to be returned without actually being stored when a null-value mapping exists.

      Specified by:
      computeIfAbsent in interface ConcurrentMap<Class<?>,V>
      Specified by:
      computeIfAbsent in interface Map<Class<?>,V>
    • compute

      public V compute(Class<?> key, BiFunction<? super Class<?>,? super V,? extends V> remappingFunction)

      Overridden to correctly handle null-value mappings. The default ConcurrentMap implementation uses putIfAbsent() when get() returns null, but putIfAbsent() returns null for both "inserted successfully" and "existing value is null," causing incorrect behavior.

      Specified by:
      compute in interface ConcurrentMap<Class<?>,V>
      Specified by:
      compute in interface Map<Class<?>,V>
    • remove

      public boolean remove(Object key, Object value)
      Specified by:
      remove in interface ConcurrentMap<Class<?>,V>
      Specified by:
      remove in interface Map<Class<?>,V>
    • replace

      public boolean replace(Class<?> key, V oldValue, V newValue)
      Specified by:
      replace in interface ConcurrentMap<Class<?>,V>
      Specified by:
      replace in interface Map<Class<?>,V>
    • replace

      public V replace(Class<?> key, V value)
      Specified by:
      replace in interface ConcurrentMap<Class<?>,V>
      Specified by:
      replace in interface Map<Class<?>,V>
    • values

      public Collection<V> values()
      Specified by:
      values in interface Map<Class<?>,V>
      Overrides:
      values in class AbstractMap<Class<?>,V>
    • unmodifiableView

      public Map<Class<?>,V> unmodifiableView()
      Returns an unmodifiable view of this map that preserves ClassValue performance benefits. Unlike Collections.unmodifiableMap(), this method returns a view that maintains the fast lookup performance for Class keys.
      Returns:
      an unmodifiable view of this map with preserved performance characteristics