This question already has answers here:
How to override equals method in Java
(11 answers)
Closed 2 years ago.
I'm trying to override the equals() method that takes an Object as input.
I have the following classes in the same package
public class Herd{
int count;
boolean exists;
In the class that is overriding the method, I am trying to compare whether the Object matches the variable in position, rank, and if they are the same Class
public class Animal{
private Herd lot;
private int rank;
public boolean equals(Object animl) {
if(this.getClass() == animl.getClass() && this.rank == animl.rank && this.lot == animl.**lot**) {
return true;
}
return false;
}
I know that to compare I will use an object that has all these parameters, however, in the Animal class itself it says
for animl.rank "rank cannot be resolved or is not a field"
for animl.lot "lot cannot be resolved or is not a field"
I tried downcasting i.e. (... == (Animal) animl.rank) but it gives me an incompatible operand types error. I also try casting the rank into an int, but it gives me the above problem.
Any help appreciated.
You need to correctly cast your animl object:
public boolean equals(Object animl) {
if(this.getClass() == ((Animal) animl).getClass() && this.rank == ((Animal) animl).rank && this.lot == ((Animal) animl).lot) {
return true;
}
return false;
}
I think it would be better if you use equals instead of =:
public boolean equals(Object animl) {
if(this.getClass() == ((Animal) animl).getClass() && this.rank.equals( ((Animal) animl).rank) && this.lot.equals( ((Animal) animl).lot)) {
return true;
}
return false;
}
Try this :
private Herd lot;
private int rank;
public boolean equals(Object animl) {
if(!(animl instanceof Animal))) {
return false;
}
Animal an = (Animal)animl;
return this.rank == an.rank && this.lot == an.lot;
}
You might need getters for those attributes. I didn't compile or test any of this.
Comparison will not work this way.
The messages:
for animl.rank "rank cannot be resolved or is not a field"
for animl.lot "lot cannot be resolved or is not a field"
are correct because there are no such properties in Object class. They only exist in your Animal class.
That said, you will need to explicitly cast the Object to Animal before doing the actual comparison. Try this:
public class Animal{
private Herd lot;
private int rank;
public boolean equals(Object animl) {
Animal animal = (Animal) animl;
if(this.getClass() == animal.getClass() && this.rank == animal.rank && this.lot == animal.lot) {
return true;
}
return false;
}
On a side note, you may need to do nested comparison for this.lot == animal.lot
Method equals in class Animal should be overridden like this:
Check for null and class equality
Cast the object to compare to Animal
Compare fields of Animal class, paying attention to using equals for the Herd
public class Animal {
// ...
#Override
public boolean equals(Object o) {
if (o == null || this.getClass() != o.getClass()) {
return false;
}
if (this == o) return true;
Animal animal = (Animal) o;
return this.rank == animal.rank &&
this.lot != null && this.lot.equals(animal.lot);
}
}
Similarly, method equals may need to be overridden in Herd:
public class Herd {
// ...
#Override
public boolean equals(Object o) {
if (o == null || this.getClass() != o.getClass()) {
return false;
}
if (this == o) return true;
Herd herd = (Herd) o;
return this.count == herd.count && this.exists == herd.exists;
}
}
Related
I have a class Animal with three properties
class Animal {
String name;
String type;
String color;
}
From a list of animals I need to find distinct animals.
The equality conditions are
if name is same both are equal
If both type and color are equal both are equal
So I wrote a wrapper animal and override the equals and hashcode
class WrapperAnimal {
Animal insideDto;
public WrapperAnimal(Animal dto) {
this.insideDto = dto;
}
public Animal unwrap() {
return insideDto;
}
#Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
}
Animal dto = ((Animal) o).unwrap();
if(dto.getName() != null && StringUtils.equals(dto.getName(), this.insideDto.getName())) {
return true;
}
return StringUtils.equals(dto.getType(), this.insideDto.getType()) &&
StringUtils.equals(dto.getColor(), this.insideDto.getColor());
}
#Override
public int hashCode() {
if(StringUtils.isNotEmpty(this.insideDto.getName())) {
return Objects.hash(this.insideDto.getName());
}
return Objects.hash(this.insideDto.getType(),this.insideDto.getColor());
}
}
I used streams distinct to find distinct
List<Animal> distinctAnimals = animals.stream().map(WrapperAnimal::new).distinct().map(WrapperAnimal::unwrap).toList()
This is not working when names are different but type and color are same.
Name
Type
Color
tiger1
type1
yellow
tiger2
type1
yellow
I understand this is issue with the hashcode function. How can I fix this?
I've a class A which is as follows:
A{
String name;
ArrayList<Bike> firstArray;
ArrayList<Cycle> secondArray;
// it's constructors and related methods are down lines.
}
and I have two instances of it named a_Obj and b_obj. I compare only the variable ,name inside object a_Obj with b_Obj using indexOf.
My question is how to call indexOf in this case and in other words how to tell the compiler that I just want to compare name of two objects regardless of ArrayLists declared inside the class A.
you can override equals() in your class
Given below is how indexOf has been implemented by default:
public int indexOf(Object o) {
ListIterator<E> it = listIterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return it.previousIndex();
} else {
while (it.hasNext())
if (o.equals(it.next()))
return it.previousIndex();
}
return -1;
}
By overriding the equals method in A to consider just the equality of name, you can make it happen.
Given below is the definition generated by Eclipse IDE:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
A other = (A) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
A shorter version for the same can be as follows:
#Override
public boolean equals(Object obj) {
if (obj == null)
return false;
A other = (A) obj;
return Objects.equals(name, other.name);
}
This is the way we implement equals method in classes.
Class A (Store) with area as instance variable:
#Override
public boolean equals(Object otherObject) {
if (this == otherObject) {
return true;
}
if (otherObject == null || getClass() != otherObject.getClass()) {
return false;
}
Store otherStore = (Store) otherObject;
return area == otherStore.area;
}
Class B (StoreToys) extends Class A (Store) and has no instance variables (dealing with inheritance)
How should i write equals method for this class?
If you don't introduce any new fields in StoreToys you can write the check with instanceof to verify that otherObject can be cast to Store.
#Override
public boolean equals(Object otherObject) {
if (this == otherObject) {
return true;
}
if (!(otherObject instanceof Store)) {
return false;
}
Store otherStore = (Store) otherObject;
return area == otherStore.area;
}
I was make some code and found that objects ar eno equals - it is trivial question but not understand how default equals works.
class A {
String id;
public A(String id) {
this.id = id;
}
public static void main(String args[])
{
A a = new A("1");
A b = new A("1");
System.out.println(a.id);
System.out.println(b.id);
System.out.println(a.equals(b));
}
}
Result is:
1
1
false
But I want to have a.equals(b) == true why it is false?
Your class currently extends only Object class and in Object class equals method looks like this
public boolean equals(Object obj) {
return (this == obj);
}
What you need is to override this method, for example like this
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
A other = (A) obj;
if (id == other.id)
return true;
if (id == null)
return false;
if (other.id == null)
return false;
if (!this.id.equals(other.id))
return false;
return true;
}
Also when you override equals you probably should override hashCode method, but this is not subject of your question. You can read more about it here.
If you don't override equals() on the object, you are comparing two different memory references. So override equals() to compare the id fields.
It overrides Object's equals method by default, it checks the "same object" rather than "same content". If you want to have a.equals(b) == true, you should override it:
#Override
public boolean equals (Object obj) {
if (obj instanceof A) {
A a = (A) obj;
if (id == null) {
return a.id == null;
} else {
return id.equals(a.id);
}
}
return false;
}
----- EDITED -----
you should rewrite an equals() method for your code, as you would a toString() method.
I want to override "public boolean equals(Object obj)" function, for name and age, in my class named MyObject whose structure is given below
public class MyObject{
private String name;
private int age;
}
How can i ?
#balusC :
What about this ?
vo = new MyObject() {
public boolean equals(Object obj) {
return ((MyObject)obj).name().equals(this.getName());
}
vo = new MyObject() {
public boolean equals(Object obj) {
return ((MyObject)obj).age() == (this.getAge());
Your question is a bit vague, but if the sole purpose is to have different sorting algorithms depending on what property you'd like to use, then rather use a Comparator.
public class Person {
private String name;
private int age;
public static Comparator COMPARE_BY_NAME = new Comparator<Person>() {
public int compare(Person one, Person other) {
return one.name.compareTo(other.name);
}
}
public static Comparator COMPARE_BY_AGE = new Comparator<Person>() {
public int compare(Person one, Person other) {
return one.age > other.age ? 1
: one.age < other.age ? -1
: 0; // Maybe compare by name here? I.e. if same age, then order by name instead.
}
}
// Add/generate getters/setters/equals()/hashCode()/toString()
}
which you can use as follows:
List<Person> persons = createItSomehow();
Collections.sort(persons, Person.COMPARE_BY_NAME);
System.out.println(persons); // Ordered by name.
Collections.sort(persons, Person.COMPARE_BY_AGE);
System.out.println(persons); // Ordered by age.
As to the actual equals() implementation, I'd rather let it return true when the both Person objects are techically or naturally identical. You can use either a DB-generated PK for this to compare on technical identity:
public class Person {
private Long id;
public boolean equals(Object object) {
return (object instanceof Person) && (id != null)
? id.equals(((Person) object).id)
: (object == this);
}
}
or just compare every property to compare on natural identity:
public class Person {
private String name;
private int age;
public boolean equals(Object object) {
// Basic checks.
if (object == this) return true;
if (object == null || getClass() != object.getClass()) return false;
// Property checks.
Person other = (Person) object;
if (name == null ? other.name != null : !name.equals(other.name)) return false;
if (age != other.age) return false;
// All passed.
return true;
}
}
Don't forget to override hashCode() as well when you override equals().
See also:
Object ordering
Sorting an ArrayList of objects
Overriding equals() and hashCode()
I'm not exactly sure what you're aiming at with this. The general expectation of equals() is that it returns false for null and objects of other classes and performs value equality on the relevant fields of the class in question.
While you can certainly handle String and Integer in the following way:
public boolean equals(Object o) {
if (o == null) return false;
if (o instanceof String) return name.equals(o);
if (o instanceof Integer) return ((Integer)o) == age;
...
}
this breaks the contract for equals so you can't do it (except not without things going wrong in very weird ways).
equals is an equivalence relation, so it has to be reflexive, symmetric and transitive. The symmetric part here is key, since if a.equals(b) then b.equals(a). Both String and Integer won't do that for you.
If you want just helper functions that check whether the name or the age is equals to a given name/age, then you can do that without using equals():
public boolean equalsName(String name) { return name.equals(this.name); }
public boolean equalsAge(int age) { return age == this.age; }
Just keep it short and simple (aka KISS principle): write setters and getters. Something like in the following example:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
And then in the method you need to do the check you can write:
Person person = new Person();
if(person.getName().equals("Something")) doThis();
if(person.getAge() == 1337) doThat();
Not sure what you mean by "multiple equals()". If you want compare both your fields, you just need to override the equals method like this,
public boolean equals( Object o )
{
if ( o != null && o instanceof MyObject )
{
MyObject m = (MyObject) o;
if (this.name == null)
return false;
return this.name.eqauls(m.name) && this.age == m.age;
}
return false;
}
/// Compute a hash code for the pair.
public int hashCode()
{
int code = name == null ? 0 : name.hashCode();
return code ^ age;
}
It's a good practice to change hashCode whenever you change equals so HashMap works efficiently with your object.
if you do want to override equals, it should look something like this:
static private <T> boolean checkEquals(T t1, T t2)
{
return (t1 == null) ? (t2 == null) : t1.equals(t2);
}
#Override public boolean equals (Object o)
{
if (o instanceof MyObject)
{
MyObject obj = (MyObject)o;
return checkEquals(this.name, obj.getName())
&& this.age == o.getAge();
}
else
return false;
}
#Override public int hashCode()
{
// implement hashCode
}
You need to override both hashCode() and equals() or neither. And you also should make sure your class is final, otherwise there are potential pitfalls with equals.
public class MyObject {
private String name;
private int age;
#Override
public boolean equals(Object o){
if(o instanceof MyObject){
MyObject otherObject = (MyObject)o;
if(name == null){
return otherObject.name == null && otherObject.age == age;
} else {
return name.equals(otherObject.name) && otherObject.age == age;
}
} else {
return false;
}
}
// When we overriding equals it is a good practice to override hashCode
// for consistecy
#Override
public int hashCode(){
int nameCode = (name == null) ? 0 : name.hashCode();
// See Item 9 in book Effective Java 2nd Edition
return 31 * nameCode + age;
}
}