Witscale Test Center

9.4 Binary operators > 9.4.6 Comparison operators


9.4.6 Comparison operators

Beside arithmetic, another most common operation that we perform while playing with numbers is to compare them. The comparison operators compare two values and return the result of comparison as a boolean value. That makes them a perfect candidate for specifying conditions in the if statements and loop statements.  Usually numeric comparisons are of two types:

1. Relational Comparison

Sometimes you need to compare whether the number is relatively greater or smaller than the other number. Java provides four relational comparison operators. < (less-than), <= (less-than-or-equal-to), > (greater-than) and >= (greater-than-or-equal-to).

2. Equality Comparisons

Another type of comparison checks whether the two numbers are equal or not. Java provides two equality comparison operators.  == (equal-to), != (not-equal-to).

You can apply the relational operators to only numeric types whereas the equality operators can be applied to all primitives and object references. Java has one more comparison operator, the instanceof operator, which is used to check the type of its operand.

Relational comparison operators

You can compare the values of all numeric types (including char) with the help of relational operators <, >, <= and >=.  The result of comparison is always a boolean value. For instance, if the operator < than is applied to two numbers, it returns true is first number is less-than the second number. Following code example shows usage for all four operators.

 

int a = 2;

byte b = 5;

char c = 'y';

float f = 2.73f;

boolean result1 = a > b;  // value of result1 will be false

boolean result2 = f < b;  // value of result2 will be true

boolean result3 = c >= f; // value of result3 will be true

boolean result4 = f <= a; // value of result4 will be false

 

You can compare any numeric value with other numeric value. For instance, you can compare a byte value with int value or a float value with a char value. However, you cannot use relational operators to compare non-numeric values such as boolean values or object references.

Equality comparison operators ==, != for primitives

The operators == (equal-to) and != (not-equal-to) tests its operands for equality and inequality respectively. When primitives are compared, the two operands are said to be equal when the value they represent is equal. You can compare value of any numeric type with the value of any numeric type. The following code compares a float value 8.0 with int value 8.

 

float f = 8.0f;

int i = 8;

if (f == i)

System.out.println("Equal"); // Equal is printed

 

At the time of execution, int value 8 is promoted to float value 8.0 and then it is compared with 8.0. You can also compare boolean operands with the  == and != operators. The following code shows the usage of inequality operator !=  for comparing boolean operands.

 

float f = 8.0

int i = 8;

boolean isGreater = (f > i);

if (isGreater != true)           // boolean inequality comparison

  System.out.println("8.0 is not greater than 8");

 

You cannot compare a boolean operand with a numeric operand.

Equality comparison operators ==, != for object references

You can compare objects for equality by comparing their references. This kind of comparison is usually of limited value. The object references are sort of memory addresses of the objects. Two object references can possibly be equal only when they both are pointing to the same object. However, it is not very helpful to compare an object with itself, as it will be equal anyway. In reality, you often need to compare two object’s contents while comparing them for equality. Say for instance, if you have two date objects representing some date then you are likely to compare them to see if both represent same date. Following code creates two date objects and compares their object references.

 

Date d1 = new Date(69,08,20);

Date d2 = new Date(69,08,20);

boolean isEqual = (d1 == d2) // isEqual will be false

 

The date objects are created with a new keyword. They are two distinct objects on memory heap. Note that the object references of two different objects are never same. Therefore d1 ===d2 will always be false. The correct way for comparing the contents of the two date objects is to call their equals() method. This method is originally defined in java.lang.Object class and has following signature:

 

        public boolean equals(Object anObject)

 

The Date class overrides this method to perform the content comparison. It takes an Object type of argument and compares the current date instance with the argument object. This method returns true if both objects represent the same date value. Thus, you can compare the date objects semantically as:

 

Date d1 = new Date(69,08,20);

Date d2 = new Date(69,08,20);

boolean isEqual = d1.equals(d2); // returns true

 

Since both date objects represent the same date, the equals() method returns true. The default implementation of equals() method in java.lang.Object class compares object references. Therefore, it returns true only when both object references are same. If you are writing your own class and you want the objects of your class to be compared based on their contents, you should override the equals() method.

 

In case of object references, the equality comparison with == is actually an identity test for objects as it returns true only when the objects are same (identical). On the other hand, the equals() methods actually does the equality test. This terminology is not very important from exam’s point of view. However, it may help you to remember the difference between == and equals() method.

 

Equality comparison operators ==, != for Strings

Strings are java objects. Therefore you can compare strings with ==, != and equals() method. However, the results of these comparisons are sometimes surprising if you do not know how the strings are created.

 

String creation

Java creates string objects in two different ways:

 

Using the new keyword

Enclosing a sequence of characters in double quotes (string literals)

 


The new keyword always creates object on heap. Every time you create a string with new keyword, a brand-new string object is created on memory heap. On the other hand, the string literals are created on special area of memory heap called the runtime constants pool (sometimes called as literal pool). When you are creating a string literal, it may not always result in a new string object. When Java runtime encounters the literal, it first checks if the same literal already exists in string pool. If not, then it creates a new string object and put it on literal pool. If the string literal you are creating already exists on the literal pool, then Java does not create a new string. For instance, the following code fragment creates three string objects:

 

 

The new keyword will always create a new string object. Therefore, line 2 and 3 will create two separate string objects on memory heap. The figure 9.5 shows the memory model after the above code is executed.

 


Figure 9.5 Memory model after the string objects are created on heap and literal pool

 

At line 1, the literal "Hello World" is first searched on the literal pool. If it is not present, a new literal is created and message1 will point to it. When Java executes line 4, the literal "Hello World" is already present on literal pool. Therefore, message4 will simply point to it.

 

String identity

Strings are considered as identical when they refer to the same string object. Since there can be only one string literal for particular sequence of characters, two string literals with same contents are always identical. Therefore, from the previous code fragment, we can say that string literals on line 1 and 4 are identical.

 

boolean isIdentical =  (message1==message4);    // true

 

On the other hand, the string objects created on line 2 and 3with new keyword point to two different string objects. Therefore, even if their contents are same, they are not identical.

 

boolean isIdentical = (message1==message2);     // false

 

 

String Equality

If you wish to semantically compare the two strings so that their contents are compared, you need to use the equals() method. The java.lang.String class overrides this method to compare the string contents. You can compare whether two string are equal by calling this method. Since all the strings shown in figure 9.5 have same content, they are all equal. Following code checks their equality as:

 

boolean isEqual = message1.equals(message2); // true

boolean isEqual = message2.equals(message3); // true

boolean isEqual = message3.equals(message4); // true

 

A call to equals() on a string object returns true if the object passed as an argument is of type String and two strings have same contents. If you pass object of different type to a equals() method on string object, the result is always false. Following code example passes a StringBuffer object as argument to equals() method on string object.

 

StringBuffer message1 = new StringBuffer("Hello World");

String message2 = "Hello World";

boolean isEqual = message2.equals(message1);      // false

 

The value of isEqual is false after this code is executed, because a StringBuffer object can never be equal to a string object.

The instanceof operator

The instanceof operator checks the type (that is the class or interface) of an object at runtime. The first operand can be any object reference variable and the second operand must be a class, interface or array type. For example, you can check whether the given object is of type String as:

 

String message = "Hello World!";

boolean isInstanceOfString = message instanceof String; // true

 


After the code is executed, the isInstanceOfString will be true. By looking at the code, it is obvious as message is indeed an instance of String. However, the instanceof operator is especially useful when the type of the object is not so obviously known. For example, if you like to check the type of objects stored in collection, you can use it. The Java collections are storage structures for objects. When you request an element from Java collection, it returns the object with type Object. Some times, you need to be sure about type of object it is returning. You can use the instanceof operator to check the type of object. Listing 9.1 has a method getFaculty() that reads from a collection staff.

 

The instanceof operator checks whether the object that the collection, faculties is returning is indeed an instance of a Faculty class. If this check is not performed and if the object returned is not of type Faculty then a ClassCastException may occur at runtime if we forcefully cast the object to type Faculty.

 

Usage of instanceof operator with superclasses

You can test the object reference not only against its own class but also against any of its superclasses. For example, assume that you have BankAccount class, which has superclass Account.

 

class BankAccount extends Account {}

 

If you apply the instanceof operators to a BankAccount object, it will return true for BankAccount class as well as its superclass, the Account class.

 

BankAccount account = new BankAccount();

boolean isAccount = account instanceof Account;           // true

boolean isBankAccount = account instanceof BankAccount;   // true

 

In fact, the instanceof operator on a BankAccount object (as first operand) and any of its superclasses as second operand always returns true. Following code applies the instanceof operator to check if the BankAccount object is-an-instance-of the Object class.

 

BankAccount account = new BankAccount();

boolean isObject = account instanceof Object;           // true

 

As the Object class is a superclass of BankAccount, isObject is true. In fact, the Object class is the superclass of all classes, hence the instanceof applied to any non-null object reference with  Object as second operand is always true.

 

Usage of instanceof operator with interfaces

If you want to check whether a particular object (actually that object’s class) implements a particular interface, you can use the instanceof operator. For instance, assume that you have BankAccount class, which implements an interface, called Auditable. The following code confirms that a object of BankAccount class implements interface type Auditable with instanceof operator.

 

BankAccount account = new BankAccount();

boolean isAccount = account instanceof BankAccount;   // true

boolean isAuditable = account instanceof Auditable;   // true

 

Thus, account is of class-type BankAccount and it is also of an interface-type Auditable.

 

Use of instanceof with interface may sound odd, as interfaces do not have instances. However, keep in mind that instanceof really checks the type of an object. When a class implements a particular interface, all of its objects are of that interface type.

 

Usage of instanceof operator with arrays

You can also use the instanceof to test whether the given object reference refers to an array. Since arrays are objects, you can use the instanceof with array references just the same way you use it with object references. For instance, if you have an array of 5 int primitives, you can test it with instanceof as:

 

int [] arr = new int[5];

boolean isAnIntArray = arr instanceof int[];      // true

 

The instanceof first checks whether the isAnIntArray is an array reference. In addition, it checks whether the elements’ type matches with the array reference type  int.  You can also check the array reference for an array of object references. Following code has array of BankAccount object references.

 

BankAccount[] arr = new BankAccount[5];

boolean isBankAccountArray = arr instanceOf BankAccount[]; // true

 

The instanceof first checks whether the isBankAccountArray is an array reference. Then it checks whether the elements’ type matches with the array reference type  BankAccount.

 

Things to remember while using the instanceof operator

The second operand of instance of specifies types in the form of class or interface name. You cannot use a string representing the name of the class. For example, the following code will not compile:

 

String message = "Hello World!";

boolean isString = message instanceof “String”; //Error!

 

You cannot use an object reference of type java.lang.Class as the second operand. Following code tries to use the Class object reference as second operand:

 

String message = "Hello World!";

boolean isString = message instanceof message.getClass(); //Error!

 

Note that getClass() method returns an object reference, whereas the second operator of instanceof should be an identifier representing class or interface name.

 

You can use instanceof operator on null reference type. It returns false regardless of the type you have specified in the second operand. Note that it does not throw a NullPointerException.