I have created a class called student which has an equals method as shown below.
My problem is this.
I create an instance of student class and add it to ArrayList, Now I want to check weather the list contains a duplicate of student object. When i try this with the below equals function its giving wrong result.
for eg.
Student stud1= new Student(101,"Student1");
Student stud5= new Student(105,"Student5");
Student stud6= new Student(105,"Student5");
list1.add(stud1);
list1.add(stud5);
System.out.println(list1.contains( new Student(105,"Student5")));// outputting false
class Student{
int sid;
String sname;
public Student(int sid,String sname){
this.sid=sid;
this.sname=sname;
}
public String toString(){
return ""+this.sid;
}
public boolean equals(Student test){
return this.sid==test.sid;
}
}
but when I replace the equals function with the one below its giving a correct result.. Why is that? Technically there is no difference right? Could you please help me as how is the JVM looking at the code..
public boolean equals(Object cond){
if(cond instanceof Student){
Student test = (Student) cond;
return test.sid==this.sid;
}
return false;
}
The first equals(Student) method doesn't override the Object#equals(Object) method. Hence with that, the list.contains(Student) method will invoke the default Object#equals() method, and which compares the references using ==. So, for two different objects, it will return false.
The contains javadoc states
Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
You must override equals(Object), in your example you define equals(Student), which is not used when calling list1.contains(.
No, they are not the same.
In order for the equals to work properly, you need to override the method from superclass (Object). And the overridden method signature is
public boolean equals(Object cond){}
By doing this public boolean equals(Student test){} you are effectively overloading the method. Thus it is no longer the call back method and the equals method of Object is getting called.
public boolean equals(Object cond)
and
public boolean equals(Student cond)
has two different method signatures
The first one, You are overriding the Object class's equals method. (Same signature as Object.equals
The second one you overload the method. with different signature.
to override, the method signature must be similar.
That is why equals(Object other) works.
Related
I am trying to sync users between two different locations, therefore I keep existing users in a list, and hence do a comparison at a set time interval to see if the user should be added (new) or just updated.
I have a class User that is the subclass to Principal.
However my compare on the list does not work; I googled a bit and found that you have to override the equals method, and I do - but that code does not seem to be executed, it goes into ArrayList.class (primitive) and executes the contains method there.
Is this because my class already extends the superclass Principal?
What are my options if I want to execute the equals that I defined in User class?
public class User extends Principal
{
// some protected properties
...
#Override
public boolean equals(Object obj) {
return (this.getAlias().equals(((User) obj).getAlias())
&& this.getEmailAddress().equals(((User) obj).getEmailAddress()) && this.getCellNumber().equals(((User) obj).getCellNumber()));
}
}
The Principal class does not override the equals method, and more importantly, the properties I check for equality, is only contained in the subclass - User. Therefore it makes sense to check it here.
So in short, I have an ArrayList of Users, and I would like to check whether a certain User already exists or not. I call compare on the list, but it always fails, indicative that the method equals is not overrided properly in my code.
Any suggestions?
You should not implement equals() (and hashcode()) in a super class.
The reason is that when equals() returns true hashcode() must return same value
Imagine you have class Point2D and class Point3D extending the other.
Shall a point2D be equal to a point3D with same area coordinates?
If so then point3D must return the same hashcode as the "equal" point2D and that means that you cannot not store more that one poin3d with same area coordinates in a Hash bases collection (eg.: as keys in a HashMap).
Overriding equals is not as evident as it looks
equals with null must return false
equals with an object of a different class must return false because of symetry a.equals(b) <=> b.equals(a)
java
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass()!=getClass()) {
return false;
}
return Object.equals(this.getAlias(),((User) obj).getAlias())
&& Object.equals(this.getEmailAddress(),((User) obj).getEmailAddress())
&& Object.equals(this.getCellNumber(),((User) obj).getCellNumber()));
}
Also if object is used in hash collections it must override hashCode so that two objects that are equals must return the same hashCode, the contrary is not true.
The problem probably comes from you instantiating a List<Person>. The compiler can't know if every subclasses of Person override equals. To correct this, you should promise your compiler you'll override this method, which you can do by changing your Person class to an abstract class.
public abstract class Person {
#Override
public abstract boolean equals(Object o);
}
public class User extends Person {
// Some stuff...
#Override
public boolean equals(Object o) {
if (o == null || ! (o instanceof User))
return false;
// etc
}
}
According to the book Effective Java.If you have override the equals method,then you must override the hashcode method.
some advice when you override the equals method:
1. equals with null return false.
2. !(obj instanceof this) return false.
3. cast obj to this class and compare the parameters in the obj and this class.
return the result in the end
You should use the contains methode of the arrayList
https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html
Assuming I have this two classes, in separate files:
public class Text
{
public String _word;
public Text(String w)
{
_word = w;
}
public String getWord()
{
return _word;
}
public boolean equals (Text other)
{
return ((other!=null)&&(_word.equals(other._word)));
}
public boolean test (Text other)
{
return 1==1;
}
}
2nd class:
public class Sentence
{
public String _word;
public Sentence(String w)
{
_word = w;
}
public String getWord()
{
return _word;
}
public boolean equals (Object other)
{
return ((other!=null) && (other instanceof Sentence)
&& (_word.equals(((Sentence) other)._word)));
}
}
And the following main:
public static void main(String[]args){
Text y1 = new Text("abc");
Sentence z1 = new Sentence ("abc");
**
}
Let's say I run the following command where ** is:
System.out.println (y1.equals(z1));
Everything is ok, and it outputs "false".
But, if I run this command:
System.out.println (y1.test(z1));
The compiler screams "Sentence can not be converted to Text".
Two questions:
Why it works for equals but not for test? y1 is Text, so calling y1.equlas() calls to equlas() inside Text, and there it gets only Text as parameter.
If it DOES work, why the output is false? both "_word" set to "abc".
Thanks!
You've defined an equals(Text) method in Text. However, it doesn't override the existing equals(Object) method that it inherits from Object. Because of this, your equals(Text) method overloads the equals(Object) method in Object. Consequently, you can call y1.equals(z1). Because z1 is a Sentence, the equals(Object) method is the one called. The Sentence object matches Object but not Text. The equals method in Object compares object references to see if they're identical.
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).
They're not, so it returns false.
You've defined a test(Text) method in Text. There are no other overloads available, and Sentence doesn't match Text at all, so the compiler complains.
Incidentally, the equals(Object) method you've defined in Sentence is a proper override of equals, checking for null and the class of the argument.
According to the Object class definition, you inherit this in all classes
public boolean equals(Object obj)
In your case y1.equals(z1) is actually executed as y1.equals( (Object) z1), a valid cast since all objects inherit Object. You then have the above method called.
I think in Text.java you wanted to override Object.equals(Object other), but instead of overriding you created an other method with the same name (equals(Text other)), but with different parameter type.
That is why System.out.println (y1.equals(z1)); compiles: that equals call matches the signature equals(Object), which method Text inherits from Object.
On the other hand, System.out.println (y1.test(z1)); fails to compile, since Text has only 1 method with the name test, and its formal parameter type is Text, which doesn't match the type of the actual parameter (Sentence).
I have the following funtion that checks if a List of codigos contains a single codigos object:
if (!concorrente.getJcodigoses().contains(cod))
{
return "redirect:" + referrer;
}
I read that i need to Override the equals method like so:
#Override
public boolean equals(Object object)
{
boolean isEqual= false;
if (object != null && object instanceof Jcodigos)
{
isEqual = (this.id == ((Jcodigos) object).id);
}
return isEqual;
}
I placed it in my Jcodigos.java class and i noticed that concorrente.getJcodigoses().contains(... never gets into my custom equals method...
Any advice?
Thanks
Answer:
I was missing the following method
#Override
public int hashCode() {
return this.id;
}
You need to provide an complmentary hashCode() method whenever providing an equals() method and visa-versa.
The reason for this is to fulfil the API contracts when interacting with the objects in collections. See the site for tips on creating the code hashcode-equals
The Java Docs have more information about the requirements. As stated in the documentation about the equals method:
Note that it is generally necessary to override the hashCode method
whenever this method is overridden, so as to maintain the general
contract for the hashCode method, which states that equal objects must
have equal hash codes.
You have to implement hashCode as well.
When we override the equals() method in Java, I know that Object needs to be a parameter, but I wonder - why Object?.
Second, let us say we override hashcode() and implement equals(), but set the parameter in equals() to MyClass instead of Object (MyClass being the class whose equals() method we override). Will we still get the expected behavior if we use HashMap?
Update: Yes, it will be overloading instead of overriding. But what will happen if we use HashMap with overloaded equals()? Also, I don't find the answer in related posts. Or is it something obvious that I am missing?
If you write an equals() method whose parameter is not Object, you are overloading the method, not overriding it.
Now, as for HashMap - HashMap calls equals to compare keys. The type of the compared keys is Object. Therefore, if you define an equals() method with a parameter whose not Object, this method will be ignored by HashMap.
I tried the following code :
public class SomeClass
{
int privateMember;
// note it's important to override hashCode, since if the hashCode of two
// keys is not the same, equals() won't be called at all
public int hashCode ()
{
return privateMember;
}
public boolean equals (Object other)
{
if (other instanceof SomeClass) {
return this.privateMember==((SomeClass)other).privateMember;
}
else {
return false;
}
}
public static void main(String[] args)
{
HashMap<SomeClass,String> map = new HashMap<SomeClass,String>();
SomeClass s1 = new SomeClass ();
SomeClass s2 = new SomeClass ();
s1.priv=4;
s2.priv=4;
map.put (s1, "something");
if (map.containsKey (s2)) {
System.out.println ("found!");
} else {
System.out.println ("not found!");
}
}
}
This code outputs "found!".
Now, if you run the exact same code, but replace the equals method with :
public boolean equals (SomeClass other)
{
if (other instanceof SomeClass) {
return this.privateMember==((SomeClass)other).privateMember;
}
else {
return false;
}
}
The output will be "not found!", which means our equals method was ignored.
The collections use the equals and hashcode methods from the Object base class. Therefore you must override them in order for your custom class to provide an implementation. You can overload equals if you wish, and that would work for situations where some code knows that it's dealing with an instance of MyClass. However, this would be misleading.
All the collections classes are designed to work with instances of Object and Object provides a general purpose equals method.
You shouldn't really need to write an equals method directly. You can either generate one using your IDE, or use EqualsBuilder from Apache Commons (https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/builder/EqualsBuilder.html) to help put it all together.
This is what my method at the moment looks like:
//this method should check if the pokemon are equal//
public boolean equals(Pokemon other){
boolean equality;
if (**XXXXX** == other)
equality = true;
else
equality = false;
return equality;
}
So this is supposed to compare two objects, but my question is how do I call the object that the method is being applied to? For instance, the main code should apply this equals method to Pokemon a, which looks like:
if (a.equals(other))
System.out.println("Pokemon are equal!");
How do I input or call "a" (the object the method is applied to) into my method so that it compares them to be equal? Because when I replace XXXXX in the code to look like:
if (Pokemon == other)
equality = true;
I get the error:
Pokemon.java:130: error: cannot find symbol
if ( Pokemon == other)
^
symbol: variable Pokemon
location: class Pokemon
Since you're calling .equals() on your object a, the method executes with a as its context, meaning the this keyword will refer to a inside of that method, just like any other method called on any other object.
Also, be careful with using ==. That will see if the two references refer to the same exact object in memory. It is highly unlikely that this is only what you want. More likely you will want to check various member variables on the two Pokemon objects to see if those variables are equal, and then if they are return true to indicate the two Pokemon objects are indeed equal. The variables you choose are up to you and your criteria for what makes two Pokemon "equal".
Often, there will actually be a == check at the beginning of a .equals() implementation, because if it's true, then the method can return true immediately since the references are referring to the exact same object in memory. If the == is false, then you can continue checking member variables or whatever other criteria you have for computing equality.
Note also that you're overloading the .equals() method by giving its arguments signature a reference of type Pokemon instead of type Object. If you want to truly override the base Object.equals() method, you'll want to do:
public boolean equals(Object other) {
// Comparisons
}
You'll need to cast other to a Pokemon object (and use instanceof) if you want to use methods and member variables specific to the Pokemon class. You need this override if you want other JDK (or even your own) code that uses .equals() to call your custom .equals() method, instead of the base Object.equals() one.
You should override the equals method provided by Object within your Pokemon class like this:
#Override
public boolean equals(Object o)
{
// check if the "addresses" of o and this object are the same
if (this == o)
return true;
// check if o is of instance Pokemon
else if (o instanceof Pokemon)
{
// need to convert Object to Pokemon - it is save as we already know that
// the o is actually a Pokemon instance
Pokemon p = (Pokemon)o;
// compare fields of o with fields of this instance
if ((this.someField.equals(p.someField)
&& (....))
return true;
}
return false;
}
Here the equals method first checks if both objects refer to the same instance, if not it checks if o is of instance Pokemon and then compares every single field you need to identify if both objects are equal.
Note however, that this example is incomplete as I don't know what fields you have defined for your Pokemon class. When overriding equals() it is good practice to also override public int hashCode() - here you should include every field you compare in equals within your returning hashCode(). Further reading: http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20 http://www.javaranch.com/journal/2002/10/equalhash.html
That's what the this keyword does.