Object equal method? - java

Below is written in javadocs
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).
Does it mean object1.equals(object2) return true only when object1==object2.
Below example at In Java, what is a shallow copy?
class Foo { private Bar myBar; ...
public Foo shallowCopy() {
Foo newFoo = new Foo(); newFoo.myBar = myBar; return newFoo; }
public Foo deepCopy() { Foo newFoo = new Foo(); newFoo.myBar = myBar.clone(); //or new Bar(myBar) or myBar.deepCopy or ... return newFoo; } } Foo myFoo = new Foo();
Foo sFoo = myFoo.shallowCopy();
Foo dFoo = myFoo.deepCopy();
myFoo.myBar == sFoo.myBar => true
myFoo.myBar.equals(sFoo.myBar) => true
myFoo.myBar == dFoo.myBar => false
myFoo.myBar.equals(dFoo.myBar) => true
If First understading is correct how come myFoo.myBar.equals(dFoo.myBar) => true

The default implementation for equals is the same as ==
However it is common practice to override this method and give it an implementation where two objects are equal if the type and contents are the same. It should always be true when == is true.

No, o1.equals(o2) should return true when o1 == o2 is true, but it can also return true under other circumstances.
o1 == o2 returns true if o1 and o2 reference the same object, i.e. the same piece of memory.
However we're often interested in whether two objects are the same based on their properties other than their location in memory. For example if I execute new String("Hello World") twice, then the two strings are the same based on the sequence of characters they represent, but they are not the same object in memory.
The JavaDocs are talking about the implementation of equals() provided by the Object class itself, which returns true when the == operator returns true. When you create a subclass of object, you can re-implement the equals method to provide the kind of equality described above.

Related

When do we say Object1 .equals(Object2) is true?

I have below code written:
public class Test{
int a;
public static void main(String[] args){
Test t1 = new Test();
Test t2 = new Test();
if(!t1.equals(t2))
System.out.println("They're not equal");
if(t1 instanceof Test)
System.out.println("True");
}
}
And here is the Output:
They're not equal
True
I even tried to assign the same value to instance variable 'a' of both these objects, like below,
t1.a = 10;
t2.a = 10;
Still the same output.
May I know when the t1.equals(t2) will return True?
How does the equals() method work on objects?
By default, calling equals execute the equals method of Object class, which returns true only when you are comparing an instance to itself.
You can override this method in other classes, so that equals would return true when the properties of both objects are equal.
For example :
#Override
public boolean equals(Object other)
{
if (other == null)
return false;
if (other instance of Test) {
Test t = (test) other;
return this.a == t.a;
}
return false;
}
Adding this method to your Test class would change the result of t1.equals(t2) to true.
The Object.equals(Object) Javadoc says (in part),
Indicates whether some other object is "equal to" this one.
The equals method implements an equivalence relation on non-null object references:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
For your code you could override equals like
#Override
public boolean equals(Object o) {
if (o instanceof Test) {
return ((Test) o).a == a;
}
return false;
}
The default implementation of Object.equals treats two objects as equal only if they are exactly the same object, not just the same contents but the same reference.
Objects can have different implementations of equals, but you must program them explicitly: if you want to check that all fields are equal, you must actually write an equals implementation that checks that.

Check if list of objects contains a String

I have the below class with the fields name and id -
public class MyObj {
private String name;
private String id;
//getters and setters + toString implementation
}
In my main method, I am creating a list of MyObjand adding elements to the list.
public static void main(String[] args) {
List<MyObj> myList = new ArrayList<MyObj>();
MyObj myObj1 = new MyObj();
myObj1.setName("test");
myObj1.setId("123");
myList.add(myObj1);
MyObj myObj2 = new MyObj();
myObj2.setName("testOne");
myObj2.setId("456");
myList.add(myObj2);
}
When I iterate through the list, and print the contents, I have this -
MyObj [name=test, id=123]
MyObj [name=testOne, id=456]
I want to check if my List has a string. For example, if it contains name or id? When I use the contains method, it returns false. Clearly I am doing something wrong. How do I check if a list of objects has a string?
You might want something like Java8 Stream and filter, but if I understand your question (and the answers and comments) you want to get all the MyObj matching a criteria?
In that case, equals is not the way to do it. eg:
MyObj a = ...
a.setName("A");
a.equals("A"); // returns true
"A".equals(a); // returns false!
The javadoc of equals says that:
The equals method implements an equivalence relation on non-null
object references:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or
consistently return false, provided no information used in equals
comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
And in that case, you have a non symmetric equals (even if javadocs says it should be rather than it must be).
You can use filter, or better Java 8's Stream.
In pre Java 8, for loops, or external library such as Guava is the way to go.
The "simple" use case is the following:
List<MyObj> matching = new ArrayList<>();
for (MyObj o : list) {
if (null != o.getName() || null != o.getId()) {
matching.add(o);
}
}
This says that you have either a name defined (eg: not null), either an id.
If you need to go further, with advanced criteria, you can do that:
interface Predicate<T> {
boolean test(#Nullable T value);
}
public class Lists {
static <T> List<T> filter(List<? extends T> list, Predicate<T> predicate) {
List<MyObj> matching = new ArrayList<>();
for (MyObj o : list) {
if (predicate.test(o)) {
matching.add(o);
}
}
return matching;
}
}
And an example:
Lists.filter(listMyObj, new Predicate<MyObj>() {
public boolean test(MyObj o) {
return null != o.getName() || null != o.getId();
}
});
But you should use Guava since it does the same, and better (my example is more or less what Guava does).
As for Java 8:
myList.stream()
.filter(o -> null != o.getName() || null != o.getId())
.collect(Collectors.toList())
And I think you can do better using MyObj::getName/getId and some Function wrapper, to do the "isNull" test.
You need to implement equals method in your MyObj

When does a.equals(a) return false?

I was wondering which are the cases where a variable in java could not be equal
(using the equals() method) to itself.
I am not talking object here but the variable itself
(as long as the code compiles and return false when calling equals).
The only situation in which it does that I found so far is:
public class A {
public static void main(String args[]){
A a = new A();
System.out.println(a.equals((a = null)));
}
}
Is there any other case in which a.equals(a) would return false?
EDIT: no overriding of equals() is allowed but you can Modify (cast, inherit) a as much as you want as long as the variable a compare itself in the end.
It could return false in multithreaded contexts, even with an equals implementation that fulfills the equals contract:
class Test {
public static final A a = new A();
public static void main(String... args) throws Exception {
new Thread() {
#Override
public void run() {
while (true) {
a.x += 1;
}
}
}.start();
Thread.sleep(10);
System.out.println(a.equals(a)); // <---
}
}
class A {
int x;
#Override
public boolean equals(Object o) {
return (o instanceof A) && ((A)o).x == x;
}
}
false
From the Object documentation of Oracle:
public boolean equals(Object obj)
Indicates whether some other object is "equal to" this one.
The equals method implements an equivalence relation on non-null object references:
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
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).
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.
Parameters:
obj - the reference object with which to compare.
Returns:
true if this object is the same as the obj argument; false otherwise.
So coming back to your question and analizing the documentation
It's false when a.equals(null); and when a and b (Objects of the classes A and B respectively) are compared, i.e. a.equals(b) will return false too.
In other cases it's true, because of:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It clearly says that: not null reference to x (or a in this case):
a.equals(a); will be true
I support khale's and Frakcool's reply. In addition to that if you just need another case to get false try
System.out.println(a.equals((a = new A())));
The assignment essentially returns what is being assigned and that will equate to false if its not the calling object itself.
I don't think there is a way we can get this done, since calling equals to itself is always true. Let me explain what you're trying to achieve.
String foo = "";
bool a = foo.equals(foo); // Here true, the easy one
foo = "some value";
bool b = foo.equals(foo); // Here true, since it's changed and then compared to itself again
bool c = foo.equals(foo="some other value"); // Here should be true again, since the compiler takes first the arguments, makes the assignation, and then makes the equals method execution, so in compiler what happens is:
// 1. Make foo = "some other value"
// 2. Compares foo with foo
// Foo is already changed, so is equals to itself
I haven't tried myself, but that's what should happen.
If for some reason compiler breaks in line bool c = ... it's because equals does not receive String instantiation as a String parameter.
With a correctly implemented .equals(), a.equals(a) will never be false.
Passing an expression to the equals method:
a.equals(a = null);
is no more special than:
a.equals(b); or a.equals(null);
You're just comparing two different values, stuffing an expression into the equals calls doesn't change that.
A very interesting case is the one where you have a boxed Float, consider this code:
Float alpha = +0.0f;
Float beta = -0.0f;
boolean equal = alpha.equals(beta);
System.out.println("Equal: " + equal);
boolean equality = alpha.floatValue() == beta.floatValue();
System.out.println("Equality: " + equality);
This will print true for the first one and false for the second.
The opposite is true of the case of Float.NaN.

Why is my HashSet storing 2 identical objects with the same hashCode?

I'm doing a school assignment where I need to store a bunch of contacts. Each contact has a HashSet of social network accounts, addresses and phone numbers.
I DO NOT want to store multiple copies of the same object in my HashSet, so I have overridden the hashCode() and equals() method for each object.
But for my social network account object only,my HashSet is storing the same object twice!
I have two different objects:
SocialNetworkAccount s1 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "wallcrawler123");
SocialNetworkAccount s2 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "wallcrawler123");
s1.equals(s2) returns true and s1.hashCode() == s2.hashCode() returns true, but s1 == s2 returns false! Why?
This is the hashCode() method I'm using:
public int hashCode() {
int prime = 31;
int result = 1;
result = result*prime + type.hashCode();
result = result*prime + id.hashCode();
return result;
}
The == operator compares references. Since there are two different objects, their references will be different.
SocialNetworkAccount s1 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "wallcrawler123");
SocialNetworkAccount s2 = s1;
if (s1 == s2) {
System.out.println("The references are the same.");
}
I suspect that the problem is that your equals method is not overriding Object's equals method, which takes an Object as a parameter.
I suspect that your equals method takes a parameter of SocialNetworkAccount, not Object. I can't know for sure because you haven't posted your equals method, but it is a possible explanation. In this case, the equals method in Object is not overridden, so when HashSet (eventually) calls it, it calls Object's equals method, which compares references to see if they are the same.
If so, modify your equals method to accept an Object instead of a SocialNetworkAccount, so it overrides equals properly.
Also, using the #Override annotation will catch when a method that intends to override another method in fact does not override it.
hashCode method is used to coarsly assign entries to the table, but the equals(...) method has to return true for the two instances to be treated as identical.
Since you don't show us the equals method I assume you have not created your own version, which means the HashTable is useing the default implementation, which does a == b and your two instances are not the same instance, so that returns false, hence two entries in the table.
What you need to do is implement the equals method too:
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof SocialNetworkAccount) {
SocialNetworkAccount their = (SocialNetworkAccount)o;
return xxx.equals(their.xxx ) && yyy.equals(their.yyy) && ...;
}
return false;
}
Replace xxx and yyy and so on with the values in your class.
See the hashCode and equals contract
maybe you have done somthing like this?
SocialNetworkAccount s1 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "foo");
SocialNetworkAccount s2 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "bar");
hashSet.add(s1);
hashSet.add(s2);
s2.setNickname("foo");
System.out.println(s1.equals(s2)); // true
System.out.println(hashSet); // [FACEBOOK:foo, FACEBOOK:foo]

What does equals(Object obj) do?

I´ve often found an equals method in different places. What does it actually do? Is it important that we have to have this in every class?
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (obj == null)
{
return false;
}
if (obj instanceof Contact)
{
Contact other = (Contact)obj;
return other.getFirstName().equals(getFirstName()) &&
other.getLastName().equals(getLastName()) &&
other.getHomePhone().equals(getHomePhone()) &&
other.getCellPhone().equals(getCellPhone());
}
else
{
return false;
}
}
It redefines "equality" of objects.
By default (defined in java.lang.Object), an object is equal to another object only if it is the same instance. But you can provide custom equality logic when you override it.
For example, java.lang.String defines equality by comparing the internal character array. That's why:
String a = new String("a"); //but don't use that in programs, use simply: = "a"
String b = new String("a");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
Even though you may not need to test for equality like that, classes that you use do. For example implementations of List.contains(..) and List.indexOf(..) use .equals(..).
Check the javadoc for the exact contract required by the equals(..) method.
In many cases when overriding equals(..) you also have to override hashCode() (using the same fields). That's also specified in the javadoc.
Different classes have different criteria for what makes 2 objects "equal". Normally, equals() returns true if it is the same Object:
Object a = new Object();
Object b = new Object();
return(a.equals(b));
This will return false, eventhough they are both "Object" classes, they are not the same instance. a.equals(a) will return true.
However, in cases like a String, you can have 2 different instances but String equality is based on the literal characters that make up those Strings:
String a = new String("example");
String b = new String("example");
String c = new String("another");
a.equals(b);
a.equals(c);
These are all different instances of String, but the first equals will return true because they are both "example", but the 2nd will not because "example" isn't "another".
You won't need to override equals() for every class, only when there is a special case for equality, like a class that contains 3 Strings, but only the first String is used for determining equality. In the example you posted, there could have been another field, description which could be different for 2 different "Contacts", but 2 "Contacts" will be considered equal if those 4 criteria match (first/last name, and home/cell phone numbers), while the description matching or not matching doesn't play into whether 2 Contacts are equal.
Aside from everything given by Bozho, there are some additional things to be aware of if overriding equals:
something.equals(null) must always return false - i.e. null is not equal to anything else. This requirement is taken care of in the second if of your code.
if it is true that something == something else, then also something.equals(something else) must also be true. (i.e. identical objects must be equal) The first if of your code takes care of this.
.equals SHOULD be symetric for non-null objects, i.e. a.equals(b) should be the same as b.equals(a). Sometimes, this requirement breaks if you are subclassing and overriding equals in the parent-class and in the subclass. Often equals contains code like if (!getClass().equals(other.getClass())) return false; that at least makes sure that a diffrent object type are not equal with each other.
If you override equals you also MUST override hashCode such that the following expression holds true: if (a.equals(b)) assert a.hashCode() == b.hashCode(). I.e. the hash code of two objects that are equal to each other must be the same. Note that the reverse is not true: two objects that have the same hash code may or may not be equal to each other. Ususally, this requirement is taken care of by deriving the hashCode from the same properties that are used to determine equality of an object.
In your case, the hashCode method could be:
public int hashCode() {
return getFirstName().hashCode() +
getLastName().hashCode() +
getPhoneHome().hashCode() +
getCellPhone().hashCode();
}
If you implement Comparable that compares two objects if they are smaller, larger, or equal to each other, a.compareTo(b) == 0 should be true if and only if a.equalTo(b) == true
In many IDEs (e.g. Eclipse, IntelliJ IDEA, NetBeans) there are features that generate both equals and hashCode for you, thereby sparing you of tedious and possibly error-prone work.
The equals method is used when one wants to know if two objects are equivalent by whatever definition the objects find suitable. For example, for String objects, the equivalence is about whether the two objects represent the same character string. Thus, classes often provide their own implementation of equals that works the way that is natural for that class.
The equals method is different from == in that the latter tests for object identity, that is, whether the objects are the same (which is not necessarily the same as equivalent).
It enables you to re-define which Objects are equal and which not, for example you may define that two Person objects as equal if the Person.ID is the same or if the Weight is equal depending on the logic in your application.
See this: Overriding the java equals() method quirk
By default, the Object class equals method invokes when we do not provide the implementation for our custom class. The Object class equals method compares the object using reference.
i.e. a.equals(a); always returns true.
If we are going to provide our own implementation then we will use certain steps for object equality.
Reflexive: a.equals(a) always returns true;
Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.
Consistent: a.equals(b) should be the same result without modifying the values of a and b.
Note: default equals method check the reference i.e. == operator.
Note: For any non-null reference value a, a.equals(null) should return
false.
public class ObjectEqualExample{
public static void main(String []args){
Employee e1 = new Employee(1, "A");
Employee e2 = new Employee(1, "A");
// if we are using equals method then It should follow the some properties such as Reflexive, Symmetric, Transitive, and constistent
/*
Reflexive: a.equals(a) always returns true;
Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.
Consistent: a.equals(b) should be the same result without modifying the values of a and b.
Note: default equals method check the reference i.e. == operator.
Note: For any non-null reference value a, a.equals(null) should return false
*/
System.out.println(e1.equals(e1));
System.out.println(e1.equals(e2));
}
}
class Employee {
private int id;
private String name;
#Override
public String toString() {
return "{id ="+id+", name = "+name+"} ";
}
#Override
public boolean equals(Object o) {
// now check the referenc of both object
if(this == o) return true;
// check the type of class
if(o == null || o.getClass() != this.getClass()) return false;
// now compare the value
Employee employee = (Employee)o;
if(employee.id == this.id && employee.name.equals(this.name)) {
return true;
} else return false;
}
public int hashCode() {
// here we are using id. We can also use other logic such as prime number addition or memory address.
return id;
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
One more thing, maps use the equals method to decide if an Object is present as a key. https://docs.oracle.com/javase/8/docs/api/java/util/Map.html

Categories

Resources