by Ray Dehler (@rdehler)

For Apex classes that are expected to be used in Sets or keys for Maps, you should create equals and hashCode methods. You cannot do the same for SObjects, however; you are restricted to using a field-by-field comparison. In other words, in the following snippet, the second Account key will overwrite the first Account in the Map.
Account a1 = new Account(Name = ‘Ray Test’);
Account a2 = new Account(Name = ‘Ray Test’);
Map
theMap.put(a1, ‘first’);
theMap.put(a2, ‘second’);
System.debug(theMap);
The debug output will be:
{Account:{Name=Ray Test}=second}
Even though these are two distinct Accounts (Name is not a unique field), our Map only contains one instance.
Furthermore, when using a SObject as a key for the Map, it is possible to edit the key for this Map. While allowed, this has an unforeseen consequence. Consider the following code snippet:
Account a1 = new Account(Name = ‘Ray Test’);
Map
theMap.put(a1, ‘Value’);
System.debug(theMap);
insert a1;
System.debug(theMap);
The debug output will be:
{Account:{Name=Ray Test}=Value}
…
{Account:{Name=Ray Test, Id=001F000000pIJiDIAW}=null}
Note that the value of this Map entry was truncated. A similar result is seen when, instead of inserting, you simply change any value of the a1 object.
Note that this is NOT the case with non-SObject non-primitive data types. Here’s a sample with an Apex class as a Map key where the issue does not occur:
public class ObjectKey {
public String name;
public String anotherValue;
}
…
ObjectKey o1 = new ObjectKey();
o1.name = ‘Ray Test’;
Map
theMap.put(o1, ‘Value’);
System.debug(theMap);
o1.anotherValue = ‘Another Value’;
System.debug(theMap);
In this case, we see the following for debug logs:
{ObjectKey:[anotherValue=null, name=Ray Test]=Value}
…
{ObjectKey:[anotherValue=
Conclusion:
When planning to use an SObject as the key for a Map, be aware that it can sometimes behavein an unexpected fashion. If you are expecting to encounter a scenario where the SObject can be mutated (even indirectly, as done by an insert) once set as a key for this Map, you will lose the reference to the value for this Map for the SObject key that was mutated.