EDIT: the question is why cant I use ".contains" (override .equals() in the object) to compare object attributes (a string) instead of comparing the object itself.
Thanks JB:
Turns out I was confusing overriding compareTo() with overriding equals()
EDIT:
QUESTION REDEFINED:
Why cant I override equals to compare strings in my object:
public boolean equals(Object obj){
...
if(obj instanceof String){
String testString = (String) obj;
...
}
...
}
Or even overload for that matter:
public boolean equals(String stringObj){
...
}
I read somewhere that the compiler doesn't use logic to decide this, it uses types. So if I then call myObj.equals(stringOne + "_" + stringTwo) shouldn't this work as it knows a string is being passed?
Thanks,
Steve.
Why this code doesn't make sense:
because Comparable is supposed to respect rules: if a < b is true, then b > a must be true. You can compare an instance of your class with String, but a String can't compare with an instance of your custom class. You're thus breaking the contract of Comparable
because Vector doesn't use compareTo() to check if an element exists or not. It uses equals().
Because you shouldn't alter the nature of a class just to implement a specific use-case consisting in adding instances of this class to a list and check for duplicates. This logic should be outside of the class. You could simply loop through the list and check is an instance with the item and position already exists or not, before creating your custom class instance.
because you shouldn't use Vector for many years (since Java 2 - we're at Java 8). And since it seems the goal is to avoid duplicates, what you should use is a Set.
Do the right thing, and use a HashSet. Make sure CustomClass implements equals() and hashCode() correctly. You could also use a HashMap<CustomClassKey, CustomClass>, where CustomClassKey is a simple class containing the two fields identifying your CustomClass instances.
So this is from Head First Java (page 563)
The default behaviour of hashCode() is to generate a unique integer
for each object on the heap. So if you don’t override hashCode() in a
class, no two objects of that type can EVER be considered equal.
But a simple Test will disprove this I think.
public class Song {
private String name;
public Song(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object obj) {
Song objectSong = (Song) obj;
return this.getName().equals(objectSong.getName());
}
}
Well this will return true:
Song songA = new Song("A","B");
Song songB = new Song("A","C");
System.out.println(songA.equals(songB));
Am I missing something? What is it that the book is trying to tell me?
The default behaviour of hashCode() is to generate a unique integer
for each object on the heap. So if you don’t override hashCode() in a
class, no two objects of that type can EVER be considered equal.
You're misinterpreting. The author isn't saying that a method (that's all equals and hashCode are) can't return true for two different objects. They're saying that semantically two objects should not be considered equal if the result of their hashCode isn't equal. They are describing how hashCode should be used. If you use it differently, you may get weird and unexpected results.
You need to override hashcode so that the class behaves as expected with hashcode based collections (and anything else).
For example what happens if you put your song in a HashSet, and then try to put another one in ?
You should always override Hashcode if you override equals, and vice versa. Make sure they are consistent.
(josh bloch effective java, is a good starting point)
In Java, every object has access to the equals() method because it is
inherited from the Object class. However, this default implementation
just simply compares the memory addresses of the objects. You can
override the default implementation of the equals() method defined in
java.lang.Object. If you override the equals(), you MUST also override
hashCode(). Otherwise a violation of the general contract for
Object.hashCode will occur, which can have unexpected repercussions
when your class is in conjunction with all hash-based collections.
Source: http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20 (take a look at it, it has good examples).
Conclusion: you only need to override equals for a simple comparison. However, you SHOULD also override hashCode for other aspects, such as hash based collections.
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.
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.
First note: when you override .equals(), you absolutely MUST override .hashCode() as well, and obey the defined contract. This is no joke. If you do not obey THAT, you are doomed to encounter problems.
As to handling equality between different classes inheriting one another, if all these classes have a common member, this can be done as such:
#Override
public int hashCode()
{
return commonMember.hashCode();
}
#Override
public boolean equals(final Object o)
{
if (o == null)
return false;
if (this == o)
return true;
if (!(o instanceof BaseClass))
return false;
final BaseClass other = (BaseClass) o;
return commonMember.equals(other.commonMember); // etc -- to be completed
}
Also remember that you need to follow these rules in order to correctly implement the equals method.
Reflexive : Object must be equal to itself.
Symmetric : if a.equals(b) is true then b.equals(a) must be true.
Transitive : if a.equals(b) is true and b.equals(c) is true then c.equals(a) must be true.
Consistent : multiple invocation of equals() method must result same value until any of properties are modified. So if two objects are equals in Java they will remain equals until any of there property is modified.
Null comparison : comparing any object to null must be false and should not result in NullPointerException. For example a.equals(null) must be false, passing unknown object, which could be null, to equals in Java is is actually a Java coding best practice to avoid NullPointerException in Java.
As Andrzej Doyle rightly said, it becomes difficult to implement the Symetric and Transitive property when it's spread across multiple classes.
Object.equals() is required to be reflexive, symmetric, transitive, consistent across multiple invocations, and x.equals(null) must be false. There are no further requirements beyond that.
If equals() for a class you define does all of those things, then it's an acceptable equals() method. There is no answer to the question of how fine-grained it should be other than the one you provide yourself. You need to ask yourself: Which objects to I want to be equal?
Note, however, that you should have a good reason for making a.equals(b) true when a and b are instances of different classes, as that can make it tricky to implement a correct equals() in both classes.
This question seems to me to indicate a muddy architecture. In theory, if you want to implement .equals such that you compare only specific members of the two instances you can do this, but whether this is a good idea really depends on just what purpose these classes are intended to serve (and even then I think there are better approaches).
Are these objects, more or less, just intended to be nothing more than bags of data? If so, perhaps you should create a separate comparison class that determines whether the two objects are "equivalent enough" for the purposes you need, rather than force the objects themselves to care about some alien, unrelated class. I'd be concerned if my code were concerning itself with potentially unrelated objects just because I thought it might be a good idea for them to know about each other due to temporary convenience. Also, as Andrzej mentioned, it's very problematic for a parent class to know or care about specific implementation details of derived classes. I've seen first-hand how this causes problems both subtle and egregious.
Are the objects "doers" rather than data storage? Since your subclass D implements a method then this indicates that it's more than just a bag of data... and in this case, philosophically, I can't see how it would be a good idea to consider A and D equal based merely on a set of value fields. Compare the fields, yes. Consider them equal or equivalent? No. This sounds like a maintainability nightmare in the long haul.
Here's an example of what I think would be a better idea:
class A implements IFoo{
private int foo;
public int getFoo(){ return foo; }
}
class B implements IFoo{
private int foo;
public int getFoo(){ return foo; }
}
class CompareFoos{
public static boolean isEquivalent(IFoo a, IFoo b){
// compare here as needed and return result.
}
}
IFoo a = new A();
IFoo b = new B();
boolean result = CompareFoos.isEquivalent(a, b);
To some extent it depends on what you want the code to do. As long as you are clear what the equals method will compare then I don't see a problem necessarily. I think the problem really comes when you start making lots of sub-classes (e.g. Class E). There's a danger than that one of the sub-classes won't follow the contract so you could end up with
a.equals(e) --> true
e.equals(a) --> false
which would result in strange behaviour.
Personally I try to avoid equals comparing two different classes and returning true but I have done it a couple of times where the whole class hierarchy was under my control and final.
Consider this example -
abstract class Quadrilateral{
Quadrilateral(int l, int w){
length=l;
width=w;
}
private int length, width;
}
class Rectangle extends Quadrilateral{
Rectangle(int l, int w){super(l,w);}
}
class Square extends Quadrilateral{
Square(int l){super(l, l);}
}
Square s = new Square(3);
Rectangle r = new Rectangle(3,3);
r.equals(s);//This should be true because the rectangle and square are logically the same.
So yes, there are cases where two different classes can be equal. Though clearly this is not common.
No.
Set<Parent> p = new HashSet<>();
p.insert(new Parent(1));
p.insert(new Child(1));
Supposing those two instances are equals, does p contain a Child? Very unclear. More fun:
class Parent {
public int foo = 0;
void foo() {
foo = 1;
}
}
class Child extends Parent {
#Override
void foo() {
foo = 2;
}
}
Set<Parent> set = new HashSet<>();
for(Parent parent : set) {
parent.foo();
System.out.println(parent.foo); // 1 or 2?
}
I challenge you to know what p's element contains without spending more than 1 minute on the Javadoc pages for Set, HashSet, or equals.
The short answer is that in very limited cases (e.g. Integer and Long) it is OK for two objects of different classes to be equal, but it is so hard to pull off correctly that it is generally discouraged. It's hard enough to ensure that you create an equals() method that is Symmetric, Reflexive, and Transitive, but on top of that you should also:
create a hashCode() method that is consistent with equals()
create a compareTo() method that is consistent with equals()
further ensure that the compareTo() method is well behaved
Failure to do that can cause problems with using the objects in Sets, Trees, Hashes, and Sorted Lists.
There's a good article on the the topic of equals() based on part of Josh Bloch's book Effective Java but even that only covers equals(). The book goes into much greater detail, especially about how the problem becomes serious quickly once you start using the objects in collections.
It depends what you need, as #andrzeg said.
One additional thing. Do you want a.equals(d) to be true, but d.equals(a) to be false? when coding you will probably be using instanceof which may or may not be what you want.
I think that this question can be reduced to whether to use instanceof or getClass() in equals() implementation.
If D derives A and your inheritance hierarchy is right then indeed D IS A. It is logical to treat D as any other A and therefore you should be able to check D for equality as you would any other A.
Here is a link where Josh Bloch explains why he favors the instanceof approach.
http://www.artima.com/intv/bloch17.html
I have some doubts regarding equals and hashcode. What I have understood previously is, we need to override the hashcode() and equals() method in the object class if that class is supposed to add to the collection class or Map class. Please see the below example. I did not override the hashcode and equals method. Still I get the desired result what I want. One thing i understood that, If I want to compare two object we need to override the equals method. But in this example I am not comparing two objects, rather I am adding objects to collection or Map without overriding the hashcode and equals. Could anyone explain why do we need to override the hashcode and when?
package equalshashcode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EqualsAndHashCode {
public static void main(String[] args) {
Student student1 = new Student("A");
Student student2 = new Student("B");
List<Student> studentList = new ArrayList<Student>();
Map<Integer,Student> studentMap = new HashMap<Integer,Student>();
studentMap.put(1, student1);
studentMap.put(2, student2);
studentList.add(student1);
studentList.add(student2);
System.out.println("Student HashMap:: "+studentMap.get(1));
System.out.println("Before removing::"+studentList);
System.out.println(studentList.remove(student1));//true success
System.out.println("After removing::"+studentList);
}
}
class Student{
String name;
public Student(String pName){
this.name = pName ;
}
public String getName(){
return this.name ;
}
}
You don't always need to implement equals() and hashCode() to add elements into a collection.
For a List (such as you studentList, which is an ArrayList instance) it doesn't matter for most actions.
The only places where you need equals() and hashCode() is where "equality" of objects is relevant. And even in those places the default implementation might even be sufficient.
Equality matters in several cases, for example:
A Set can't contain two objects that are equal to each other
The key of a Map must have a correct equals() implementation to be retrievable (and based on the concrete Map implementation, that might imply that hashCode() has to be correctly implemented as well).
Some methods on a "normal" List also need equality. For example contains(), indexOf() and remove(Object) need correctly implemented equals()/hashCode()
Custom equals and hashCode methods are generally used for determining actual equality. If you rely on the default equals method, this will look for the same instance in memory. For example customObj1.equals(customObj2) will return false if there's no custom equals method and the two objects are separate (but otherwise equal) instances. The idea of a custom equals method is to make that same example return true if they are actually equal. A Map will then be able to use this to match the key object passed in a get(key) request to find the value without needing to have the correct instance of the key (a HashMap actually uses hashCode to do this).
The most obvious example of this being useful is for Strings, so that you can do myMap.get("key") and get the correct value, even if your key instance isn't the same as the one stored in the Map (String implements equals and hashCode for you). In general I would recommend using these Java built-in equals and hashCode methods to construct your own. For example if your object has a natural ID, such as say userName, your equals can use the String version of this to complete your own equals (you can obviously compare multiple fields):
public boolean equals(Object o) {
if (o instanceof MyObj) {
return userName.equals(((MyObj) o).userName));
}
return false;
}
As such, if you'll only be working with a single Thread, or otherwise limited variables, you'll likely never need to implement these methods, but there are certainly times when it pays off to know them.
Collection classes will work perfectly well with objects that have the default equals/hashCode implementations - there is no need to add your own for this reason.
Custom equals/hashCode methods are easy to get wrong, and unless you have a good reason to roll your own you should just stick with the ones that you get for free with java.lang.Object.
The most common reason for creating your own version of these methods is if you want to treat two separate instances of the same class as being equal. For example, if you have an Account class and you want two instances of Account which have the same accountNumber property to be regarded as equal, because they represent the same real-world account. In this case you would base your equals method on the value of accountNumber alone, and since you now have a custom equals method you need to provide a suitable implementation of hashCode as well, in order to fulfil the equals/hashCode contract.
Only interesting, why method hashCode() in java.lang.String is not static?
And in case of null return e.g. -1 ?
Because frequently need do somethihg like:
String s;
.............
if (s==null) {
return 0;}
else {
return s.hashCode();
}
Thanks.
As others have noted hashCode is a method on Object and is non-static because it inherently relies (i.e. belongs to) an object/instance.
Note that Java 7 introduced the Objects class, which has the hashCode(Object) method, which does exactly what you want: return o.hashCode() if o is non-null or 0 otherwise.
This class also has other methods that deal with possibly-null values, such as equals(Object, Object), toString(Object) and a few others.
because if it was static "1".hashCode() and "2".hashCode() would have returned the same value, which is obviously wrong.
It is specific per instance, and influenced by it, therefore it cannot be static.
Because the hash code of a String is a property of that String.
With the same train of thought you could make every method static.
hashCode is used to get the hashCode of an object, in order to know in which bucket of a HashMap this object must be placed. It thus has to be an instance method of the object, and it must be called polymorphically.
null can be used as a key in a HashMap, but it's treated as a special case.
You seem to be using hashCode for a different purpose, so you have to handle is in a specific way.
Its returning hashCode of an Object not an class.