I'm trying to write some generic code to define class equality and hashcodes based on a list of fields. When writing my equals method, I was wondering if, based on Java convention, it should ever be possible for two object of different to be equal. Let me give some examples;
class A { int foo; } class B { int foo; } class C extends A { int bar; } class D extends A { void doStuff() { } } ... A a = new A(); a.foo = 1; B b = new B(); b.foo = 1; C c = new C(); c.foo = 1; c.bar = 2; D d = new D(); d.foo = 1; a.equals(b); //Should return false, obviously a.equals(c); c.equals(a); //These two must be the same result, so I'd assume it must be false, since c cant possible equal a a.equals(d); //Now this one is where I'm stuck.
I see no reason that in the last example the two shouldn't be equal, but they do have different classes. Anyone know what convention dictates? And if they would be equal, how should an equals method handle that?
Edit: if anyone's interested in the code behind this question, see: https://gist.github.com/thomaswp/5816085 It's a little dirty but I'd welcome comments on the gist.
In Java, the == operator compares that two references are identical or not. Whereas the equals() method compares two objects. Objects are equal when they have the same state (usually comparing variables).
equals in Java? The equals() method is a static method of the Objects class that accepts two objects and checks if the objects are equal. If both the objects point to null , then equals() returns true .
Every Object in Java includes an equals() and a hashcode() method, but they must be overridden to work properly. To understand how overriding works with equals() and hashcode() , we can study their implementation in the core Java classes. Below is the equals() method in the Object class.
This can occur through simple assignment, as shown in the following example. Value equality means that two objects contain the same value or values. For primitive value types such as int or bool, tests for value equality are straightforward.
They could be, but it's typically very difficult to maintain the symmetric and transitive properties of equality in that case. At least while having a useful/intuitive definition of equality.
If you allow a subclass to consider itself equal to an instance of the superclass, then the superclass needs to consider itself equal to an instance of the subclass. Which means that you'll be encoding specific knowledge about the subclass (all possible subclasses?) in the superclass, and downcasting as needed, which isn't very clean.
Or, you do the comparison purely with fields contained in A
, and don't override equals()
at all. This fixes the above, but has the problem that two instances of C
with different values of bar
would be considered equal, which is probably not what you want.
Or, you override in C
, and compare bar
if the other object is an instance of C
, but otherwise don't for an instance of A
, you have another problem. c1.equals(c2)
would be false, but c1.equals(a)
would be true, as would c2.equals(a)
and so a.equals(c2)
. This breaks transitivity (since c1 == a
and a == c2
implies c1 == c2
).
In summary, it's theoretically possible but you would have to cripple your equals implementation to do so. And besides, the runtime class is a property of an object just as much as bar
is, so I'd expect objects with different concrete classes to be not equal to each other anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With