Allocation, identity, and cost
Identity vs state, the boxed-numeric cache trap, and why allocation cost is measured, not assumed.
new = a heap allocation: address, header, initialized fields. Every
allocation produces an object with identity distinct from its state:
Integer a = 100, b = 100; // a == b — small-value cache shares one object
Integer c = 500, d = 500; // c != d — outside the cache: two allocations
== compares identity (same allocation?); equals compares state. The
small-Integer cache (-128..127) is an implementation choice, not a contract —
comparing boxed numerics with == is a latent bug that passes on small
numbers and detonates on large ones.
An object's address is observable only weakly (identityHashCode is not
the address, but its stability reflects the same object) — yet the fact of
allocation is very observable: memory consumed, GC pressure, allocation
rate. Advanced Java allocates deliberately: escape analysis can stack-allocate
non-escaping objects, and scalar replacement can dissolve them entirely —
which is why "allocation is expensive" is a claim to measure, not assume.