3.10 Equality

Primitive Data Value Equality: ==, !=

Given that a and b represent operands of primitive data types, the primitive data value equality operators are defined as shown in Table 3.7.

Table 3.7. Primitive Data Value Equality Operators

a == b

a and b are equal? That is, have the same primitive value? (Equality)

a != b

a and b are not equal? That is, do not have the same primitive value? (Inequality)

The equality operator == and the inequality operator != can be used to compare primitive data values, including boolean values. Binary numeric promotion is applied to the nonboolean operands of these equality operators.

int year = 2002;
boolean isEven  = year % 2 == 0;     // true.
boolean compare = '1' == 1;          // false. Binary numeric promotion applied.
boolean test    = compare == false;  // true.

Care must be exercised in comparing floating-point numbers for equality, as an infinite number of floating-point values can be stored in a finite number of bits only as approximations. For example, the expression (1.0 - 2.0/3.0 == 1.0/3.0) returns false, although mathematically the result should be true.

Analogous to the discussion for relational operators, mathematical expressions like a = b = c must be written using relational and logical/conditional operators. Since equality operators have left associativity, the evaluation of the expression a == b == c would proceed as follows: ((a == b) == c). Evaluation of (a == b) would yield a boolean value that is permitted as an operand of a data value equality operator, but (<boolean value> == c) would be illegal if c had a numeric type. This is illustrated in the examples below. The expression at (1) is illegal, but those at (2) and (3) are legal.

int a, b, c;
a = b = c = 5;
boolean valid1 = a == b == c;               // (1) Illegal.
boolean valid2 = a == b && b == c;          // (2) Legal.
boolean valid3 = a == b == true;            // (3) Legal.

Object Reference Equality: ==, !=

The equality operator == and the inequality operator != can be applied to object references to test whether they denote the same object. Given that r and s are reference variables, the reference equality operators are defined as shown in Table 3.8.

Table 3.8. Reference Equality Operators

r == s

r and s are equal? That is, have the same reference value? (Equality)

r != s

r and s are not equal? That is, do not have the same reference value? (Inequality)

The operands must be type compatible: it must be possible to cast one into the other's type; otherwise, it is a compile-time error. Type compatibility of references is discussed in Section 6.6.

Pizza pizza_A = new Pizza("Sweet&Sour");      // new object
Pizza pizza_B = new Pizza("Sweet&Sour");      // new object
Pizza pizza_C = new Pizza("Hot&Spicy");       // new object

String banner = "Come and get it!";           // new object
boolean test  = banner  == pizza_A;           // (1) Compile-time error.
boolean test1 = pizza_A == pizza_B;           // false
boolean test2 = pizza_A == pizza_C;           // false

pizza_A = pizza_B;                        // Denote the same object, are aliases.
boolean test3 = pizza_A == pizza_B;       // true

The comparison banner == pizza_A in (1) is illegal, because String and Pizza types are not type compatible. The values of test1 and test2 are false, because the three references denote different objects, regardless of the fact that pizza_A and pizza_B are both sweet and sour pizzas. The value of test3 is true, because now both pizza_A and pizza_B denote the same object.

The equality and inequality operators are applied to object references to check whether two references denote the same object or not. The state of the objects that the references denote is not compared. This is the same as testing whether the references are aliases, that is, denoting the same object.

The null reference can be assigned to any reference variable, and an object reference in a reference variable can be compared for equality with the null reference. The comparison can be used to avoid inadvertent use of a reference variable that does not denote any object.

if (objRef != null) {
    // ... use objRef ...
}

Object Value Equality

The Object class provides the method public boolean equals(Object obj), which can be overridden (see Section 6.2, p. 233) to give the right semantics of object value equality. The default implementation of this method in the Object class returns true only if the object is compared with itself, that is, as if the equality operator == had been used to compare aliases to the object. This means that if a class does not override the semantics of the equals() method from the Object class, then object value equality is the same as object reference equality. For a detailed discussion on implementing the equals() method, see Section 11.7 on page 461.

Certain classes in the standard API override the equals() method, for example, java.lang.String, java.util.BitSet, java.util.Date, java.io.File and the wrapper classes for the primitive data types. For two String objects, value equality means they contain the same character sequence. For the wrapper classes, value equality means that the primitive values in the two wrapper objects are equal.

// Equality for String objects means same character sequence.
String movie1 = new String("The Revenge of the Exception Handler");
String movie2 = new String("High Noon at the Java Corral");
String movie3 = new String("The Revenge of the Exception Handler");
boolean test0 = movie1.equals(movie2);             // false
boolean test1 = movie1.equals(movie3);             // true

// Equality for Boolean objects means same primitive value
Boolean flag1 = new Boolean(true);
Boolean flag2 = new Boolean(true);
boolean test2 = flag1.equals(flag2);               // true

// Pizza class does not override the equals() method,
// can use either equals (inherited from Object) or ==.
Pizza pizza1 = new Pizza("VeggiesDelight");
Pizza pizza2 = new Pizza("VeggiesDelight");
Pizza pizza3 = new Pizza("CheeseDelight");
boolean test3 = pizza1.equals(pizza2);             // false
boolean test4 = pizza1.equals(pizza3);             // false
boolean test5 = pizza1 == pizza2;                  // false
pizza1 = pizza2;                                   // Aliases
boolean test7 = pizza1.equals(pizza2);             // true
boolean test6 = pizza1 == pizza2;                  // true