== versus equals()

Most answers on the internet are incomplete and some are even plain wrong. I’ll try to list all differences.

Short answer

  • == checks if two expressions have the same value.
  • equals checks if two objects represent the same thing.

But that doesn’t really answer it. It is important to understand what those values are and what it means when two objects are equal. In a job interview you must give a short and precise answer but that is difficult for this question.

== basically checks if two expressions represent the same value and in most cases this means that the same bits and bytes are used to represent that value. But there are exceptions from this basic rules. I explain those later.
When you use == on two objects then you check for identity. Same identity simply means that two objects are the same (just one object). Java actually just applies == to the values of the references, without accessing the objects.

equals is used to check two objects for equality. This usually means that you could replace one for the other and that both should have the same hash code. Therefore an object is usually equal to itself. Equal Sets contain equal elements, equal Strings represent the same text, equal DateFormats represent the same format, and so on.

Basic Definitions

(x and y are different variables with different memory content)

== (Equality Operator)

  • Compares values (primitives / references)
  • == is an operator
  • x == x can be false! x == y can be true!
  • != is always the exact opposite of ==
  • Two values/objects are:
    • identical (5 == 5)
    • or distinct ("A" == "B").

equals (Method)

  • Compares two objects (of any type)
  • equals is a method
  • Default behaviour (without overriding implementation) is:
    • x.equals(x) is true
    • x.equals(y) is false
    •  x.equals(null) is false
  • x.equals(x) can be false! x.equals(y) can be true!
  • Two objects are:
    • equal ("A".equals("A"))
    • or unequal/different ("A".equals("B"))

Special Cases

There are exceptions and it is important to know  them.

Special Cases of ==

This operator sometimes doesn’t return what you might expect.

Values of different Types can be considered identical

int i = 42;
byte b = 42;

i and b are considered to be identical. But in memory they are different in size. Java will cast b to int and then compare two integers.

NaN is not NaN

Double.NaN == Double.NaN // => false

This is false. But that’s just the nature of NaN. In this case the memory holds the same value.
The JVM even knows two types of NaN, but that isn’t relevant here.

+0 is -0

+0.0 == -0.0 // => true

A double uses one bit for the sign (+/-). So the memory holds different values. But they are the same by definition.

null is null

In contrast to NaN there is no special rule for null.
A variable that references null does not reference any valid object. In SQL the expression NULL = NULL evaluates to false. But in Java you get true for null == null. Why? Because!

== is not = from Math Lessons

0.1+0.2 != 3.0/10.0

There is no precise representation of tenths in IEEE 754 floating point numbers. Therefore both expressions are actually a bit larger than 0.3, but not by the same amount.
To compare two floating point values you should always calculate the absolute difference and compare that to some delta.

double a = 0.1 + 0.2;
double b = 3.0 / 10.0;
double delta = 0.0000001;
boolean equal = Math.abs(a - b) < delta;

Special Cases of equals

This method sometimes doesn’t return what you might expect.

Values of different Types can be equal

A proper implementation should define some type (class or interface) that needs to be used by two objects to be considered equal.
For example a HashSet can be equal to a TreeSet. But it only works if there is a common type that defines equality (in that case the java.util.Set interface).
In many other cases there is no such common type:

((Integer) 1).equals(1.0) // => false

Both are of type Number, but Integer would not consider any object to be equal that isn’t also an Integer.

String and int do not share any common type that would allow them to be equal, so the values are not equal.

"42".equals(42) // => false

NaN equals NaN

((Double) Double.NaN).equals(Double.NaN) // => true

This is actually true, even though NaN != NaN

+0 and -0 are not equal

… but this is false:

Double.valueOf(+0.0).equals(Double.valueOf(-0.0)) // => false

This is important so that all instances of Double can be used in Collections using equals (Map, Set).

null

You get a NullPointerException for null.equals(x).

x.equals(null) should return false.

How to implement equals?

Just read the api specs:
http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-

It’s actually a bit more complex in some situations. Here’s a complete guide:
http://www.artima.com/lejava/articles/equality.html

Leave a Reply

Your email address will not be published. Required fields are marked *