This week's book giveaway is in the Other Open Source APIs forum. We're giving away four copies of Storm Applied and have Sean Allen, Peter Pathirana & Matthew Jankowski on-line! See this thread for details.
First of all, let's write down the contract for Object.equals again. I will need it later on. 1) It is reflexive: for any non-null reference value x, x.equals(x) should return true. 2) It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true. 3) It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true. 4) It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified. 5) For any non-null reference value x, x.equals(null) should return false.
This is mostly how I do it:
Now some comment: 1) If it is the same references, by returning true you will skip the other checks. Especially the class specific checks could take a lot of time and memory. It also takes care of contract rule #1 immediately.
2) Most people use the following:
However, this will in many cases break the contract for Object.equals. Let's take this code:
This clearly violates the second rule of the contract!
Of course you loose a lot of flexibility because instances of subclasses will never be equal to instances of their superclass, but that's a price you need to pay.
By references i didnt mean to check the reference of the instances.
I mean that if i have class User that have Address and Company as a members ,so in the equals i need to write all the bla bla about check the instanceof and etc and also check the address , company equality...
It seems that you need to check the equality of all attriutes include collection and complext objects but i didnt saw any one that write equals like this and this is a major performane impact.
[avihai]: It seems that you need to check the equality of all attriutes include collection and complext objects but i didnt saw any one that write equals like this and this is a major performane impact.
Well, performance impacts are all relative. Checking equality of all attributes is surely slower than using == would be, but that doesn't mean it's a problem. In many cases, it's completely trivial, and if there is a performance bottleneck in your code, it's elsewhere. So I wouldn't worry about it pre-emptively. Moreover, if you've got two different instances whose data may be equivalent, you may very well need to write an equals method that compares all the attributes. The fact that == would be faster is irrelevant if == doesn't do the job you need it to.
And in practice, I have seen plenty of code with equals() methods that check the equality of each and every attribute. It's fairly standard in m experience.
Here the obj == this test is an early shortcut - if it's true, you can skip everything else. And we're relying on the Collection implementations to have usable equals() implementations (which they do, generally, though you may need to consider whether order should be important or not) and those implementations will presumably rely on the implementations of Address.equals() and Company.equals() to determine the equality of whatever sub-fields they have. (And if an Address or Company has a link back to the User you'll have an infinite loop, so be careful.)
In some cases you may be able to determine equality with a subset of the fields - e.g. maybe it's enough to just check the name, or maybe there's a userID field which is guaranteed to be unique to each customer. However this could get confusing if there are ever two User instances with the same userID but different addresses or companies - you'd need some logic to manage things carefully so that doesn't happen, or so the two Users are either kept separate, or merged somehow, or you can identify one as "more accurate" and discard the other. [ September 20, 2007: Message edited by: Jim Yingst ]
"I'm not back." - Bill Harding, Twister
Joined: Jan 10, 2007
== is not an option at all. equals you need to check with equals . the probelem is that if you will run equals object has a references to a lot of other objects and they have a references to a lot ob objects and etc you will find yourself go to the data base for each object and load a lot of objects to the memory.
the probelem is that if you will run equals object has a references to a lot of other objects and they have a references to a lot ...
An alternative is to not override equals() and define instead
which does all the ugly and slow comparisons deep into the object tree.
If you need it, you can call it
Joined: Jan 30, 2000
[avihai]: the probelem is that if you will run equals object has a references to a lot of other objects and they have a references to a lot ob objects and etc you will find yourself go to the data base for each object and load a lot of objects to the memory.
Well, now wait a minute. If some of the objects aren't in memory, how do you plan to load them? Will they be looked up using a primary key, or some other set of unique criteria? If so, then you may well not have to fully load all of the other objects - you can just compare the primary keys / unique criteria which you would use to load, without loading those objects. For example if company names are unique, and used to load a Company object, you don't need to load the entire Company object from a database - you can just use the name of the company in your equals comparison.
In general there should be no need to go to a database in order to implement equals(). If there is, then maybe you should consider doing the entire equality comparison on the database, not in your JVM. But when you talk about collections, that normally refers to objects which are already in memory, not sitting in a database. For objects which are in memory, yes, I would usually implement equals() as I have shown above. Maybe it's slow, but if it's necessary (as you indicate it is), then it's necessary.
Going back to your User example - is the name unique? Maybe not. But there's a good chance that some other attribute (or combination of attributes) is unique. Perhaps there's a Social Security number, or a comany-issued customerID code. If so, then you don't need to compare all those other attributes - just compare the customerID codes.
[Pat]: An alternative is to not override equals() and define instead equalsSlowAndDeep() which does all the ugly and slow comparisons deep into the object tree.
True, but to my mind that has very limited usefulness. You can't use this object in HashMap or HashSet, for example, since that will call the regular equals(). In fact, if doing something like this I would probably override equals() to throw an UnsupportedOperationException, to make sure no one accidentally used it and got incorrect results. And even then, I have a hard time seeing what the use of this method is. Unless there is somehow a shorter version of equals that is actually useful for something - but I don't know what a good example of that would be. If there's only one useful way to implement equals(), then I would call it equals(), no matter how slow it is, and maybe warn people with a comment if it seems overly slow.