Overriding the Object class' equal method - java

OK so so let's say you have two classes: ClassA and ClassB
ClassA extends Object and ClassB extends ClassA
ClassA has no argument constructor
ClassB has an integer variable x and a constructor with an integer argument that initializes x
ClassA doesn't override equals that it's inhering from Object
ClassB overrides equals so that two objects of ClassB are considered equal if the integer x has the same value in both objects.
//In Class B you have this method:
public boolean equals (Object obj) {
if (obj == null) {
return false;
}
if (obj.getClass() != this.getClass()) {
return false;
}
if (!super.equals(obj)) {
return false;
}
B b = (B) obj;
return this.x == b.x;
}
In the main if you were to run this code
B b1 = new B(1);
B b2 = new B(1);
System.out.println(b1.equals(b2));
I believe "false" would be printed but I'm trying to understand why. Maybe I'm not fully understanding the concept of overriding but I just figured since B should be overriding the Object.equals method so it can make sure the x fields are the same.
What appears to be "wrong" that I'm missing?

You should omit the
if (!super.equals(obj))
{
return false;
}
because that will use the default equals() method (which checks for object identity)

Your code is never going to get past the super.equals check, because (since Object.equals is comparing object references) any two different objects are always going to test false for equality. Object.equals is comparing references, the only time it returns true is if it is comparing a reference to itself.
Typically if you override equals it is because you want to compare the objects by value (like String or BigInteger), so there is no reason for referencing the super class's equals method (which compares by reference) in that case.

Related

How to use an object that was called from a method in Java?

I'm trying to figure out what the syntax is for calling an object inside a method..
Pseudocode:
boolean check(Object someObject) {
return someObject == theOtherObject;
}
public static void main(String args[]) {
someClass one = new someClass();
someClass two = new someClass();
one.check(two);
}
So the check method is supposed to check whether the two objects are equal, but how would I specify the other object (theOtherObject should be one)?
Thanks in advance!
One word answer: this
boolean check(Object someObject) {
return someObject == this;
}
which will test object identity only. You should override equals and use that.
if (one.equals(two)) {
// ...
}
You can have the boolean check(Object o) method inside SomeClass and check
boolean check(Object o) {
this == (SomeClass) o;
}
This would work only if both reference variables are pointing to same object. Moreover the right way to check if two objects are meaningfully equal would be to use the inherited equals and hashCode method.
Override equals and hashCode method.
Why do I need to override the equals and hashCode methods in Java?
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-
So what you're asking for there is actually already a command in java.lang.Objects class to compare to objects.
one.equals(two)
the comparison this does is called a shallow comparison. So if that's what you're looking to do then this would work. For reference, the definitions of shallow comparison defined by geeksforgeeks.org is
Shallow comparison: The default implementation of equals method is defined in Java.lang.Object class which simply checks if two Object references (say x and y) refer to the same Object. i.e. It checks if x == y. Since Object class has no data members that define its state, it is also known as a shallow comparison.
if you're looking to do a more complicated comparison you're the best bet would be to actually override the equals command in the one class file
this article would be a good place to start to learn more about this topic.
https://www.geeksforgeeks.org/equals-hashcode-methods-java/

Instant of interface and class

In my code I have seen difference between instant of interface and instant of class that implement it , why ??
I have method that return array of objects of class and implements an interface which declare this method , when create instant of class and invoke this method the returned value is different if it was invoked by interface instant although it should do the same job , the returned value is different , why??
public interface A{
public B[] m();
}
public class B implements A {
public B[] m() {
B b[]=new B[10];
for(int i=0; i>10; i++)
b[i]=new B();
return b;
}
}
In this part when I try to create two instant one for class and another for interface then invoke the method for each one like :
B obj1=new B();
A obj2=new B();
System.out.println(obj1.m().equals(obj2.m));
System.out.println( obj1.m()[0].equals(obj2.m()[0]) );
........
This returned false.
Maybe it is clear obj1 is not obj2, but why is the returned value different and how can I get same returned value if possible?
The behavior of your code have nothing to do with the compile time type of obj1 (B) vs. obj2 (A).
The reasons your comparisons return false :
Comparing the arrays would always return false for two distinct arrays, since arrays don't override Object's equals method.
Comparing the first element of the two arrays also returns false, since your B class doesn't override the equals method, so obj1.m()[0].equals(obj2.m()[0]) is false since obj1.m()[0] != obj2.m()[0]. It can only return true if your B class would have an implementation of public boolean equals (Object other) that may return true.
You are comparing objects, that will never be same, unless you override the equals method.
You should compare the contents.
There is no difference between declaring objects, in your case
Case1: B obj1=new B();
Case2: A onj2=new B();
In case1 you are directly assigning to Object B so you are eligible to call method specific to B along with implemented methods from A.
In Case2 you are only eligible to call the methods implemented from Interface A
It is called polymorphism.
Correcting your code will give the right answer, as answered by Eran

Java getClass and super classes

public boolean equals(Object o) {
if (this == o)
return true;
if ((o == null) || (this.getClass() != o.getClass()))
return false;
else {
AlunoTE umAluno = (AlunoTE) o;
return(this.nomeEmpresa.equals(umAluno.getNomeEmpresa()) && super.equals(umAluno);
}
}
Could anyone explain me how the fourth line ((this.getClass() != o.getClass())) works when the argument is a super class? Because the classes have different names. this.getClass will return a different name than o.getClass, right?
Check the following code snippet which answers your question. Object O can hold any object. o.getClass() will return the run time class of the object
public class Main {
void method(Object o) {
System.out.println(this.getClass() == o.getClass());
}
public static void main(String[] args) {
new Main().method(new Object()); // false
new Main().method(new Main()); // true
new Main().method(new String()); // false
new Main().method(new MainOne()); // false
}
}
class MainOne extends Main
{
}
So lets say there are two classes. Class A and Class B. Class A is a super class of class B. So this method would be in class B. "this.getClass()" refers to an object of class B while o.getClass()(The super class) will refer to class A. So Class B will not equal Class A. Meaning it will go into the if statement.
Suppose your super class is SHAPE and you have a class RECT that is a subclass of SHAPE.
If the this variable is for a RECT and the Object o is also a RECT,
then line 4 will return true because they are the same class (RECT).
The two objects will be equal as long as their types are the same at runtime.
However, if Object o is of type SQUARE, which also subclasses SHAPE,
(and could even subclass RECT).
then it will not be equal to the this pointer (RECT),
because their classes are different at runtime.
Now for why this kind of type checking is bad in the equals method (specifically for the use case of Hibernate entity classes).
If you use Hibernate and you are checking a newly created object whose class type is RECT against an object whose class type was RECT at the time it was cached in Hibernate, the class of the object in the cache will actually be a sub-class of type RECT, because Hibernate does byte-code manipulation and wraps the objects in a synthetic sub-class (RECT_$$javassist).
This means that your Hibernate cached objects that you expect to be equal will never be equal.
If the object is in a child collection, Hibernate will assume you wanted to delete the old object from the collection and create the new object in the collection instead of doing a (potential) update on an existing object in the collection.
We have legacy code that did this and could never figure out why (until now) it kept doing deletes and re-inserts on our collection.
For Hibernate entity objects you should use the instanceof operator to determine if two objects could be equal - and then cast Object o and continue the comparison operation with class SHAPE specific fields.
If your subclasses should not be considered equal, then you will have to implement equals() in each subclass to check for instanceof.
For other use cases, you will have to determine if there is a chance that someone (or some other library) could sub-class your Class (even through byte code manipulation) and whether any sub-classes should still be considered equal or not.
For instance, if you do any kind of mocking in your unit tests, a bad equals method may cause otherwise equal objects to be non-equal due to their classes not being equal.
Back to the OP's code. A better way to code the equals method would be:
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof AlunoTE))
return false;
AlunoTE umAluno = (AlunoTE) o;
return(this.nomeEmpresa.equals(umAluno.getNomeEmpresa()) && super.equals(umAluno);
}
Because the instanceof operator always returns false for null, there is no need for a null check too.

Java equals for a Class. Is == same as .equals

Can we do a == on a Class variable instead of equals and expect the same result?
For example:
Class clazz = xyz;
Case A:
if(clazz == Date.class) {
// do something
}
Case B:
if(Date.class.equals(clazz)) {
// do something
}
Are Case A and Case B functionally same?
Class is final, so its equals() cannot be overridden. Its equals() method is inherited from Object which reads
public boolean equals(Object obj) {
return (this == obj);
}
So yes, they are the same thing for a Class, or any type which doesn't override equals(Object)
To answer your second question, each ClassLoader can only load a class once and will always give you the same Class for a given fully qualified name.
Yes.
Take a look at the Class class description and note that it inherits equals from Object, for which the method reads:
"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)."
Yes, since the code for equals(...) for class is the following:
public boolean equals(Object obj) {
return (this == obj);
}

In which circumstances Java reference equality could be different to equals() equality for an object of a type which has not overridden equals()?

Is there any magic hanging around anywhere that could mean that
(object0 == object1) != (object0.equals(object1))
where object0 and object1 are both of a certain type which hasn't overridden Object.equals()?
No. That's exactly the definition of Object.equals().
...this method returns true if and only if x and y refer to the same object (x == y has the value true) ...
public boolean equals( Object o ) {
return this == o;
}
Yes, if by "The type of object0 doesn't override Object.equals()" you mean the specific type and not a superclass.
If object0 and object1 are of type B, B extends A, and A overrides equals(Object obj) but B doesn't, then it is possible that B doesn't override equals(Object obj) but (object0 == object1) != (object0.equals(object1)).
Well, if object0 == null and object1 == null, the first will deliver true, and the second a NullPointerException. Apart from that, there should be no observable difference.
Although the objects don't override equals() themselves, it is possible that one of superclasses of the object overrides the equals() method.
If you are using eclipse: open the object.java file and press control-o twice. Type 'equals' and check if you only see one 'equals' method: the equals method of Object.
The Object.java src defines its equals method as;
return (this == obj)
so no :-)
Yes, null == null is true, but null.equals(null) is not defined.
No, if equals() is not overridden, it returns true if the objects are the same identical objects in memory.
Here is the source code for Object.equals:
public boolean equals(Object obj) {
151 return (this == obj);
152 }
153
So, No.
No. The actual class of object0 (not necessarily the declared type of the variable) must have overridden equals(). Try printing out:
object0.getClass()

Categories

Resources