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
Related
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.
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.
I need to create a subclass of HoverFrog called EOHoverFrog. Instances of EOHoverFrog differ from instances of HoverFrog in that two instances of EOHoverFrog are considered equal if their position and height are the same, regardless of their colour.
To do this, I need to write an instance method equals() for EOHoverFrog that overrides the equals() method inherited from Object. The method should accept an argument of any class. If the class of the argument is not the same as the class of the receiver, the method should simply return false, otherwise it should test the equality of the receiver and the argument.
public boolean equals(Object obj)
{
Frog.getClass().getHeight();
HeightOfFrog height = (HeightOfFrog) obj;
return (this.getPosition() == frog.getPosition());
}
please could you tell me whether I'm correct?
public boolean equals(Object obj) {
// my first (incorrect) attempt, read Carlos Heuberger's comment below
// if (!(obj instanceof EOHoverFrog))
// return false;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
// now we know obj is EOHoverFrog and non-null
// here check the equality for the position and height and return
// false if you have any differences, otherwise return true
}
that doesn't seem correct.
public boolean equals(Object obj)
{
Frog.getClass().getHeight(); // you arent assigning this to anything, and class probably
// doesn't have a getHeightMethod()
HeightOfFrog height = (HeightOfFrog) obj; // obj should be an EOHoverFrog; you should
// return false above this if obj is null or the
// wrong class
return (this.getPosition() == frog.getPosition()); // what is frog? It is not defined
// in your example
// you are not comparing heights anywhere.
}
A good way to implement an equals method is:
1) Make sure the other object passed in, obj in your case, is not null and the right class (or classes). In your case, can EOHoverFrog and HoverFrog instances be equal?
2) do your comparisons, something like
// assuming both height and position are on the base calss
var isHeightEqual = this.getHeight() == ((HoverFrog)obj).getHeight();
var isPositionEqual = this.getPosition() == ((HoverFrog)obj).getPosition();
3) now you are in position to check equality
return isHeightEqual && isPositionEqual;
First of all, read this to understand how each equals() method must behave.
Second, if you overrides the equals() method, then it's good practice to add #Override annotation before method.
To learn by examples, you can study a lot of equals() implementations here.
I’ve got a List<MyObject> list
And, I want to make use out of the list.contains() function.
It doesn’t seem to work at the moment, i.e. there are objects in the list that match, but is not being picked up by the comparator operator.
I’m guessing I need to write my own comparison operator in MyObject. What is the way to go about this?
You need to override public boolean equals(Object o) because contains uses it:
boolean contains(Object o)
Returns true if this collection contains the specified element. More formally, returns true if and only if this collection contains at least one element e such that (o==null ? e==null : o.equals(e)).
See How to implement hashCode and equals method for a discussion of simple and correct ways to override equals.
You need to be especially careful to override equals(Object o) and not just implement equals(MyObject o).
You only have to implement your own version of equals and hashcode on MyObject class.
The default equals will not check the attribute you define in a class. That's why you get the wrong result.
Your class needs to implement equals(). It's also useful to implement the Comparable interface, if you ever want to sort your objects E.g.
class MyObject implements Comparable<MyObject> {
public int compareTo(MyObject o) {
// do the compare!
}
public boolean equals(Object o) {
// check equality
}
}
Notice the documentation for List's contains method:
List.contains()
It states that it used the equals method to determine equality and therefore determine if the element exists in the list.
Also, note that when you overload equals you must overload hashCode.
You have to override equals() in MyObject.
public class MyObject
{
public boolean equals(Object obj)
{
if(this == obj)
return true;
if((obj == null) || (obj.getClass() != this.getClass()))
return false;
// object must be MyObject at this point
MyObject test = (MyObject) obj;
// Compare 'this' MyObject to 'test'
}
public int hashCode()
{
// generate your hash
}
}
The default behavior of Object.hashCode() is to return essentially the "address" of the object so that a.hashCode() == b.hashCode() if and only if a == b. How can I get this behavior in a user-defined class if a superclass already defines hashCode()? For instance:
class A {
public int hashCode() {
return 0;
}
}
class B extends A {
public int hashCode() {
// Now I want to return a unique hashcode for each object.
// In pythonic terms, it'd look something like:
return Object.hashCode(this);
}
}
Ideas?
System.identityHashCode(Object) provides this behaviour.
You would write this:
class B extends A {
public int hashCode() {
return System.identityHashCode(this);
}
}
Please check the equals-method, that it only returns true, if the two objects are the same. Otherwise it would break behaviour described for equals and hashCode. (To be correct, the equals-method has to return false, if you get different hashcodes for two objects.) To provide an implementation of equals() that comply with the given hashCode()-method:
public boolean equals(Object other){
return this == other;
}
Use System.identityHashCode(). This is what IdentityHashMap uses.
You should be extremely wary of overriding an existing hashCode() with this though because you might break the hashCode contract, being that two objects that:
if a.equals(b) then a.hashCode() must equal b.hashCode()
You might break this by overriding the existing behaviour or you might need to override equals() too.
As Mnementh said it all, I'd just like to point out that hashCode() returning 0 (or any constant value) is valid (while lame). hashCode() can (and should) return different values for a and b only if !a.equals(b).
So for example you have
class A {
public int hashCode() {
return 0;
}
public boolean equals(Object o) {
return o instanceof A; // all objects are equal
}
}
class B extends A {
public int hashCode() {
return System.identityHashCode(this);
}
public boolean equals(Object o) {
return this.hashCode().equals(o.hashCode());
}
}
Now you create two objects:
A a = new A();
A b = new B();
And suddenly a.equals(b), but !b.equals(a). Of course in more real life the equals() in A will be more sophisticated, but the problem still persist. To get rid of this problem you want to always call
if (super.equals(o)) return true;
at the beginning of new equals().
And since overriding hashCode() is strictly tied to overriding equals(), you want to make sure that everywhere super.equals() returned true for any two given objects, new hashCode() will return super.hashCode().