If you simply add a field, equals() and hashCode() will still fulfil their general contract, even though you will now have a peculiar definition of equality.See line 5.You can now have two cars with the same make and number but travelling at different speeds and neither equals() nor hashCode() will notice a difference. Strange, but it is a conceivable situation in real life, particularly amongst the criminal classes Your troubles will start if you update equals() or hashCode() but not both; I think updating only hashCode() will break equals() but not vice versa.
Rob Spoor wrote:. . . if you add a field . . .
John Mercier wrote:If hashCode can always return 1 and still be valid I think it would need to be tested in a way that shows it is a good hashCode.
It should be unique for everything that is equal
and different for things that are not equal
Please explain more. That sentence is rather vague. It is not always necessary to use every field in equals() but you must only use fields in hashCode() which are used in equals(). If you use a feature to calculate a hash code which isn't used to determine equality, you can have two objects equal to each other but with different hash code.
John Mercier wrote:. . . I believe that most of the time when a field is added equals and hashCode should be considered for an update and this is a common mistake but let's just assume all fields are considered.
No. Most people don't write super.equals(ob) in their equals() method, but many people write an == test, which does exactly the same.Both those partial methods will do the same, but neither will cure any problems caused by passing null as an argument. If you look at the general contract for equals(), you find it must accept null and always return false. If you look at the point about consistency, you find it should always return a result, which means no exceptions are permitted. Both the following partial methods will satisfy that requirement, but you must remember that the version with getClass() is a bit too stringent, not permitting equality with subclass objects:-Remember that instanceof returns false if its left operand is null.
The use of Objects.equals helps in preventing NullPointerExceptions.
Edit: remove rest of quote. I pushed the submit button too early.
. . .
Actually, that is only true if your superclasses don't override equals(). It is probably a bad idea to override equals() more than once because you can get transitivity failure, and you would find that difficult to test automatically. Maybe you should always make equals() a final method. Just a suggestion.
A few minutes ago, I wrote:. . . Both those partial methods will do the same . . ..
Stephan van Hulst wrote:The only test you can perform for hashCode() is that equal objects must have equal hash codes.
Campbell Ritchie wrote:Please explain more
Campbell Ritchie wrote:No. Most people don't write super.equals(ob) in their equals() method, but many people write an == test, which does exactly the same.
Whether they realise it or not, those people are creating a definition of equality which ignores those fields. Just as my Car class defined equality without using speed. Of course, ti is a lot better when people understand what they are doing, rather than its happening by default.
John Mercier wrote:. . . I often see developers add fields to classes without considering equals or hashCode at all. . . .
You always have to consider the possibility of a field being null when you write equals(). You can writeMany people wrote equality tests like that until the Objects class was introduced (Java7; it should have been Java1.1).
One time we had a field added and it was added to equals and hashcode but in a way that would cause an NPE if the field was null. . . .
I am so sorry; I misread what you wrote. I thought you said Object#equals() and you wrote Objects#equals(). I was totally mistaken about what you meant.
. . . using Objects.equals . . .
Campbell Ritchie wrote:You always have to consider the possibility of a field being null when you write equals().
Campbell Ritchie wrote:I am so sorry
John Mercier wrote:Ok I think that hashCode could be checked in the equals tests.
What I mean is I often see developers add fields to classes without considering equals or hashCode at all.
It is possible some fields are not needed in equals and hashCode
One time we had a field added and it was added to equals and hashcode but in a way that would cause an NPE if the field was null.
This is what intellij generates using Objects.equals if null members are allowed.
So I think the number of tests needed could be
5 + 2 x members + 2 x nullableMembers + 1 x superclass (can be 0)
In the case of DirectedEdge if source and target are non-null then this would be 9 tests for equals.
Stephan van Hulst wrote:No. Tests must be simple and test one specific thing.
Stephan van Hulst wrote:Classes are either value types in which case they have a definition of equality that is based on all normalized fields, or they are entities or services, in which case different instances are unequal.
Stephan van Hulst wrote:Why was the field allowed to be null? This should occur only very rarely. For instance, I don't see the purpose of having an edge with a null source or target.
Stephan van Hulst wrote:I don't like the code that IntelliJ generates, because it uses getClass(). That implies that you can't compare instances of base classes against instances of derived classes. Use instanceof instead and make your equals() method final.
Stephan van Hulst wrote:Not sure what you mean by this, but in general the number of tests you need is not a simple calculation over the number of members of a class. You don't test members. You test assumptions you make about the class. The number of assumptions depend on the class design, not the number of members.
Stephan van Hulst wrote:I'm not sure what you mean by the self test. Isn't it already covered by the reflexivity test?
John Mercier wrote:I believe The Car example where speed is ignored by Campbell Ritchie would be and entity but it seems ok to check some of the fields in the equals method. For instance if equals checked an id field for a database entity.
I think that would be fine but maybe the whole class could be final?
I'm only trying to calculate the number of tests needed for equals and hashCode in a class. Since these methods are based entirely on the members of the class I thought the number of tests could be determined ahead of time.
If you make the class final, then your equals() method can be correct whether you use instanceof or getClass(). Assuming we would permit equality to subtype objects, if you take the final modifier off the class, then you are allowed subtypes, and you can't put that modifier back. It also means you would have to change the equals() method if you used getClass().
Stephan van Hulst wrote:. . . I still prefer the instanceof operator in final classes because it also performs the null check. . . .
Stephan van Hulst wrote:assuming you wrote parameterized tests to begin with