Value-based Classes should not be used with operations that rely on object identity including reference equality, identity hashing, synchronization, or serialization.
JEP 401 introduces Value Classes and Objects as a preview feature in Java 28. Many existing JDK types (such as primitive wrappers, Optional, and java.time classes) are value-based and are migrating to become true value classes.
Operations to avoid on value classes:
Synchronization and Monitors : Value objects do not have an object monitor. Synchronizing on them or calling wait(), notify(), or notifyAll() cannot provide mutual exclusion (as the runtime may freely copy or recreate instances) and throws IdentityException.
Weak, Soft, and Identity References : Classes like WeakReference, SoftReference, and PhantomReference track the lifecycle of a specific object instance in memory. Because value objects can be flattened, inlined, or rematerialized by the JVM, tracking their lifetime is meaningless.
Identity-Based Maps and Caches : IdentityHashMap, WeakHashMap, and builder configurations like CacheBuilder.weakKeys(), CacheBuilder.weakValues(), MapMaker.weakKeys(), or Caffeine.weakKeys() rely on reference identity (==) or reference queues. Value classes will not behave correctly with identity lookup or weak eviction.
System.identityHashCode(...) : System.identityHashCode computes a hash code based on object identity. Value-based classes do not have persistent identity, so calling System.identityHashCode on them is not equivalent to val.hashCode() and produces unstable results across equal or re-boxed instances. Use Objects.hashCode(val) or val.hashCode() instead.