//Written by K@stackoverflow
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person("Subash Adhikari", 28));
people.add(new Person("K", 28));
people.add(new Person("StackOverflow", 4));
people.add(new Person("Subash Adhikari", 28));
for (int i = 0; i < people.size() - 1; i++) {
for (int y = i + 1; y <= people.size() - 1; y++) {
boolean check = people.get(i).equals(people.get(y));
System.out.println("-- " + people.get(i).getName() + " - VS - " + people.get(y).getName());
System.out.println(check);
}
}
}
}
//written by K@stackoverflow
public class Person {
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj.getClass() != this.getClass()) {
return false;
}
final Person other = (Person) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if (this.age != other.age) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 53 * hash + this.age;
return hash;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Output:
Answer from Kim on Stack Overflowrun:
-- Subash Adhikari - VS - K false
-- Subash Adhikari - VS - StackOverflow false
-- Subash Adhikari - VS - Subash Adhikari true
-- K - VS - StackOverflow false
-- K - VS - Subash Adhikari false
-- StackOverflow - VS - Subash Adhikari false
-- BUILD SUCCESSFUL (total time: 0 seconds)
Videos
//Written by K@stackoverflow
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person("Subash Adhikari", 28));
people.add(new Person("K", 28));
people.add(new Person("StackOverflow", 4));
people.add(new Person("Subash Adhikari", 28));
for (int i = 0; i < people.size() - 1; i++) {
for (int y = i + 1; y <= people.size() - 1; y++) {
boolean check = people.get(i).equals(people.get(y));
System.out.println("-- " + people.get(i).getName() + " - VS - " + people.get(y).getName());
System.out.println(check);
}
}
}
}
//written by K@stackoverflow
public class Person {
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj.getClass() != this.getClass()) {
return false;
}
final Person other = (Person) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if (this.age != other.age) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 53 * hash + this.age;
return hash;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Output:
run:
-- Subash Adhikari - VS - K false
-- Subash Adhikari - VS - StackOverflow false
-- Subash Adhikari - VS - Subash Adhikari true
-- K - VS - StackOverflow false
-- K - VS - Subash Adhikari false
-- StackOverflow - VS - Subash Adhikari false
-- BUILD SUCCESSFUL (total time: 0 seconds)
Overloading vs Overriding
Introducing a new method signature that changes the parameter types is called overloading:
public boolean equals(People other){
Here People is different than Object.
When a method signature remains the identical to that of its superclass, it is called overriding and the @Override annotation helps distinguish the two at compile-time:
@Override
public boolean equals(Object other){
Without seeing the actual declaration of age, it is difficult to say why the error appears.
So, as a beginner, I found that comparing objects with the default equals() method actually does almost exactly the same thing like comparing them with ==. In other words, if two variables reference the same object, == will resolve as true and also equals() will resolve as true. But if we have two variables referencing two objects with a different identity but semantically the same (like, hmmm they look same to me! Same variables, etc.!) we actually have to come with our own equals() method and override the Java default method. (And when doing that, why not also override HashCode(), you know).
Now my question is not the typical "why???"(technicaly why it is needed?) but "why???" (why on earth was Java language designed this way)? Why Java does not have e.g. objectsEquals() method that would work for objects comparing all the fields etc. by default?
Why it even has equals() method that works the same as operator ==? In such a universe we could also have methods isTheSame(), isCompletelyTheSame() and thisIsEqual() all doing the same stuff? And also why we are even overriding it? Is it like "Java authors designed this method poorly or too generally, so let us made our better method that does also this and that". Why not create a framework class or our own class or just completely new method like sameObjects() and just use it with our own new beatiful name? Why overriding? Sorry, I am pretending rant, but I am just trying to be a little funny and also as a beginner I do not really understand this equals() override. What I am really trying to say is, I like to understand things deeply, in this case not only, it works basically in this and that way why but why it even exists as a part of our world:-)
should we always override the equals and hashCode even if we don’t intent at that point to use the class with any Collection classes?
No and I would go even further as to say you probably don't need to override them even if you are going to put them into a collection. The default implementations are perfectly compatible with collections as is. For lists, it's irrelevant anyway.
You should override equals if and only if your objects have a logical identity that is independent of their physical identity. In other words, if you want to have multiple objects that represent the same entity. Integer, is a good example of this. The integer 2 is always 2 regardless of whether there are 100 instances or 1 of the Integer object with the value of 2.
You must override hashcode if you've overridden equals.
That's it. There are no other good reasons to modify these.
As a side note, the use of equals to implement algorithms is highly overused. I would only do this if your object has a true logical identity. In most cases, whether two objects represent the same thing is highly context dependent and it's easier and better to use a property of the object explicitly and leave equals alone. There are many pitfalls to overriding equals, especially if you are using inheritance.
An example:
Let's say you have an online store and you are writing a component that fulfills orders. You decide to override the equals() method of the Order object to be based on the order number. As far as you know, that's the it's identity representation. You query a DB every so often and create objects from the response. You take each Order object and keep it as a key in a set which is all the orders in process. But there's a problem, orders can be modified in a certain time frame. You now might get a response from the DB that contains the same Order number but with different properties.
You can't just write this object to your set because you'll lose track of what was in process. You might end up processing the same order twice. So, what are the options? You could update the equals() method to include a version number or something additional. But now you have to go through your code to figure out where you need to base the logic on the having the same order number and where you need it to be based on the new object identity. In other words, there's not just one answer to whether two objects represent the same thing. In some contexts it's the order, and in some contexts it's the order and the version.
Instead of the set, you should build a map and use the order number as the key. Now you can check for the existence of the key in the map and retrieve the other object for comparison. This is much more straightforward and easy to understand than trying to make sense of when the equals method works they way you need it to for different needs.
A good example of this kind of complexity can be found in the BigDecimal class. You might think that BigDecimal("2.0") and BigDecimal("2.00") are equal. But they are not.
Conclusion:
It can make sense to implement equals() (make sure you update hashcode() too if you do) and doing so doesn't prevent the use of any of the techniques I describe here.
But if you are doing this:
- Make sure your object is immutable
- Use every meaningful property of the object to define equals.
- If you are using inheritance, either:
- make equals final on the base class OR
- you must check that the actual type matches in subclasses
If any of these aren't followed, you are in for trouble.
In Java, if you don’t override anything, equality is defined as object references being equal, and the hash code is the bit pattern of the reference. That works just fine to put objects into containers.
And there are objects where this is exactly right. For example an object representing a window in the UI. Two windows are equal if and only if they are the same window.
PS. It makes absolutely sense to have a set of windows, or a dictionary with windows as keys, or an array of windows and lookup if the array contains some window - so you need to be able to compare windows for equality.
Regarding efficience they are equivalent efficient. There is not an impact on performance either you use the first or the second. I would prefer the first though, since it "protects" you from comparing Objects to Objects from Subclasses, which leads to strange, not expected and not consistent results.
If I have a class B extends Member then B is an instanceof Member therefor it is error prone in many cases. First solution is the best. Choose the one generated by IDE.
should I override equals function for any class that I create?
Override equals if (and only if) the object "represents some data", i.e. if it models something such as Person, Car or RecipieIngredient (these typically end up in collections etc). Don't override equals for other types of classes, for example LoginServlet or DatabaseUtil.
Remember to always override hashCode whenever you override equals.
(A natural follow-up question:) What happens if I don't override equals and hashCode?
Any two objects will be considered unequal unless they are the exact same object.
[...] I need every single attribute of it to be equal?
Typically yes. It depends on how you define your notion of equality. Note that for reference types, you can reuse/delegate to that objects implementation of equals (and hashCode) when implementing your own.
Related questions:
- why we need to override equals and hashcode in java and why cannot we use Object class implementation
- Why do I need to override the equals and hashCode methods in Java?
You should only override equals() if you have a reason to do so. As described here, it is very difficult to write a proper equals() method for non-final or mutable classes.
If your application requires some sort of equality concept that is different from "the identical object", then by all means go ahead. Just read the above reference to be aware of what's involved. But as a matter of routine? Definitely not.