Map and Set are internally based on HashMap and HashSet, respectively. In these classes, there are "buckets" created for each hashCode, and within each bucket, you have a list of values that each have the same hashCode but where equals
return false.
For performance reasons, these buckets are only calculated when calling add
or addAll
. Altering the hashCode of an object in the Map key or in a Set will cause that object to be "not found" until the internal state is reset. You can do this with System.debug, although you should not rely on that behavior being reliable.
This isn't so much a bug as it is an implementation detail. Modifying the key or a value in a set such that the hashCode changes is not supported. Attempting to do so is undefined behavior, and usually will cause issues. This is very specifically called out in the documentation:
If the object in your map keys or set elements changes after being added to the collection, it won’t be found anymore because of changed field values.
Keep in mind the following when implementing the equals method. Assuming x, y, and z are non-null instances of your class, the equals method must be:
Reflexive: x.equals(x)
Symmetric: x.equals(y) should return true if and only if y.equals(x) returns true
Transitive: if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true
Consistent: multiple invocations of x.equals(y) consistently return true or consistently return false
For any non-null reference value x, x.equals(null) should return false
Keep in mind the following when implementing the hashCode method.
If the hashCode method is invoked on the same object more than once during execution of an Apex request, it must return the same value.
If two objects are equal, based on the equals method, hashCode must return the same value.
If two objects are unequal, based on the result of the equals method, it is not required that hashCode return distinct values.
As you can see, the bits on hashCode are very specific: each object must return the same hashCode each time, two objects that return true for equals must also return the same hashCode.
Modifying an Sobject key is a specific violation of the rules, and the behavior is undefined/not supported.