Java Deep Comparison Returns False when Comparing a Deep Copy
One of the common misconceptions in Java is the use of ==
vs .equals()
. When you use ==
to compare two objects in Java, internally it's comparing its memory address. ==
does not actually call .equals()
.
In this case, you have two distinct orange objects, so the comparison will always return false.
If you use a.equals(b)
, then it will actually invoke your equals
method which you implemented.
As @Andreas pointed out in the comments, there's another issue. Calling super.equals(obj)
in Fruit
will call the superclass implementation of equals
, and the superclass of Fruit
is Object
. Object.equals()
behaves the same as ==
(i.e. also checking for reference equality). Overriding .equals()
is not trivial, so it can often be nice to have the IDE generate it for you.
In contrast with a language like C++, Java does not have operator overloading. This means that you can't define a different implementation for ==
. This is why it's best practice to always call .equals()
when comparing any non-primitive types (unless you're explicitly checking reference equality, which is rare).
Check if two objects are completely equal in Java
You have a few options for automating Equals & Hashcode (option #3 BLEW MY MIND!):
- Your IDE. I would not recommend it for most objects as they can slowly drift out of date with the actual class definition. They also look ugly and pollute your codebase with boilerplate code.
- Apache Commons has a bunch of stuff for making this easier, including a reflective version so no risk of drifting out of date with the class definition. It is better than #1 unless you require a speedy equals/hashcode, but still too much boilerplate for my liking.
- Project Lombok and annotation processing. Whack an
EqualsAndHashCode
annotation on ya class and be done with it. I recommend using Project Lombok. It adds a touch of magic into the build (but not much) and so requires a plugin for your IDE to behave nicely but they are a small price to pay for no boilerplate code. Lombok is an annotation processor that run at compile time so you have no runtime performance hit. - Using a different language that supports it out the box, but also targets the JVM. Groovy uses an annotation and Kotlin supports data classes. Unless your existing code can quickly be converted, I would avoid this.
- Google's Auto has an AutoValue. Like Project Lombok this is an annotation processor, however has less magic at the expense of little more boilerplate (thanks to Louis Wasserman)
Deep reflective compare equals
From the answer to this question https://stackoverflow.com/a/1449051/116509 and from some preliminary testing, it looks like Unitils' ReflectionAssert.assertReflectionEquals
does what you're expecting. (Edit: but may be abandoned, so you could try AssertJ https://assertj.github.io/doc/#assertj-core-recursive-comparison)
2021 edit: EqualsBuilder
now has a testRecursive
option. However the unit test libraries mentioned will give you a better failure message to help debug, so depending on context, they're still the best option.
Compare two objects excluding some fields - Java
The quickest way without writing any code is Lombok
Lombok is one of the most used libraries in java and it takes a lot of Boilerplate code off your projects. If you need to read more on what it can and does, go here.
The way to implement what you need is pretty straightforward:
// Generate the equals and HashCode functions and Include only the fields that I annotate with Include
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Getter // Generate getters for each field
@Setter // Generate setters for each field
public class Class1
{
@EqualsAndHashCode.Include // Include this field
private Long identity;
private String testStr1; // This field is not annotated with Include so it will not be included in the functions.
// ... any other fields
}
Lombok can do a lot more than this. For more information on @EqualsAndHashCode
refer to this.
You can always use @EqualsAndHashCode.Exclude
for a quicker solution to your use case:
@EqualsAndHashCode
@Getter // Generate getters for each field
@Setter // Generate setters for each field
public final class Class1 {
private String a;
private String b;
private String c;
:
:
:
private String z;
@EqualsAndHashCode.Exclude
private Date createdAt;
@EqualsAndHashCode.Exclude
private Date updatedAt;
}
What is the fastest and efficient way to check Deep Equal for two java objects?
Override equals()
or have a *helper method (bad option!) and do it in 5 steps :
1. Check for *not null*.
2. Check for same *type*.
3. Check for *size of byte[]*.
4. Check for `==` (*reference equality* of byte[])
5. Start comparing byte values
Related Topics
The Resourceconfig Instance Does Not Contain Any Root Resource Classes
Differencebetween the Float and Integer Data Type When the Size Is the Same
When Should We Create Our Own Java Exception Classes
Java - How to Load Different Versions of the Same Class
Selenium Many Logs (How to Remove)
Java Applet Game 2D Window Scrolling
Text-Mouseover Popups Over a Swing Jtextarea
Calculating Difference in Dates in Java
"Loading Class Com.Mysql.Jdbc.Driver ... Is Deprecated" Message
Java.Lang.Classcastexception Using Lambda Expressions in Spark Job on Remote Server
Get Rid of "The Value for Annotation Attribute Must Be a Constant Expression" Message
How to Get the Desktop Path in Java
Why Does Arraylist Have "Implements List"
Combine Multiple Collections into a Single Logical Collection
Why F Is Placed After Float Values
How to Get a List of Ip Connected in Same Network (Subnet) Using Java