To comment on and extend the answer from @sfdcfox, I recommend against conversion to a string in order to hash, especially if your object will be used in a Set or Map in code that is executed often, because string concatenation is slow (and generates significant amounts of garbage to be collected). More than that, since fox's suggestion is to effectively ignore whitespace and case, similar values varying only by whitespace or case will receive the same hash - this may or may not be appropriate for your use case.
My recommendation is to leverage List<Object>
since this already supports hashCode
based on its content. As long as each of the object's attributes are of types that support hashCode
(which could be your very own implementation on an Apex class using this very same approach) and your attributes are a, b, c and d, then your hashCode
function can look something like:
public Integer hashCode() {
return new List<Object>{ a, b, c, d }.hashCode();
}
Equality should use the objects' types (classes) and attribute values individually, whilst allowing for null where necessary. However, you can again leverage the power of List<Object>
to apply much of this logic (assuming your class is called MyClass
):
public Boolean equals(Object other) {
if (other instanceof MyClass) {
MyClass that = (MyClass) other;
return new List<Object>{ a, b, c, d } == new List<Object>{ that.a, that.b, that.c, that.d };
}
return false;
}
The hash use of List<Object>
is far more efficient than the equivalent string conversion/concatenation one and will always win hands down in terms of performance (we have done analysis on this on earlier versions of the Salesforce platform). The use of the list in equals is actually less efficient than individual property checks, but makes the code far shorter.
At the risk of a little more code complexity, you could implement your attributes as properties and ensure that the setters update a private List<Object>
property at the appropriate index in order to effectively cache the list through the lifecycle of your MyClass instances, though I would not recommend this approach unless it is essential for performance.
hashCode()
method provided to every class by default (by virtue of implicitly inheriting from theObject
class)?hashCode()
method when creating a custom type.