File
class? In this example, as well as during the exam, you may be presented with class names that are unfamiliar, such as File
. Many times you can answer questions about these classes without knowing the specific details of these classes. In the previous example, you should be able to answer questions that indicate monday
and tuesday
are two separate and distinct objects because the new
keyword is used, even if you are not familiar with the data types of these objects.
In some languages, comparing null
with any other value is always false
, although this is not the case in Java.
System.out.print(null == null); // true
In Chapter 4, we'll continue the discussion of object equality by introducing what it means for two different objects to be equivalent. We'll also cover String
equality and show how this can be a nontrivial topic.
Relational Operators
We now move on to relational operators, which compare two expressions and return a boolean
value. Table 2.8 describes the relational operators you need to know for the exam.
TABLE 2.8 Relational operators
Operator | Example | Description |
---|---|---|
Less than |
a < 5
|
Returns true if the value on the left is strictly less than the value on the right
|
Less than or equal to |
b <= 6
|
Returns true if the value on the left is less than or equal to the value on the right
|
Greater than |
c > 9
|
Returns true if the value on the left is strictly greater than the value on the right
|
Greater than or equal to |
3 >= d
|
Returns true if the value on the left is greater than or equal to the value on the right
|
Type comparison |
e instanceof String
|
Returns true if the reference on the left side is an instance of the type on the right side (class, interface, record, enum, annotation)
|
Numeric Comparison Operators
The first four relational operators in Table 2.8 apply only to numeric values. If the two numeric operands are not of the same data type, the smaller one is promoted, as previously discussed.
Let's look at examples of these operators in action:
int gibbonNumFeet = 2, wolfNumFeet = 4, ostrichNumFeet = 2; System.out.println(gibbonNumFeet < wolfNumFeet); // true System.out.println(gibbonNumFeet <= wolfNumFeet); // true System.out.println(gibbonNumFeet >= ostrichNumFeet); // true System.out.println(gibbonNumFeet > ostrichNumFeet); // false
Notice that the last example outputs false
, because although gibbonNumFeet
and ostrichNumFeet
have the same value, gibbonNumFeet
is not strictly greater than ostrichNumFeet
.
instanceof Operator
The final relational operator you need to know for the exam is the instanceof
operator, shown in Table 2.8. It is useful for determining whether an arbitrary object is a member of a particular class or interface at runtime.
Why wouldn't you know what class or interface an object is? As we will get into in Chapter 6, “Class Design,” Java supports polymorphism. For now, all you need to know is objects can be passed around using a variety of references. For example, all classes inherit from java.lang.Object
. This means that any instance can be assigned to an Object
reference. For example, how many objects are created and used in the following code snippet?
Integer zooTime = Integer.valueOf(9); Number num = zooTime; Object obj = zooTime;
In this example, only one object is created in memory, but there are three different references to it because Integer
inherits both Number
and Object
. This means that you can call instanceof
on any of these references with three different data types, and it will return true
for each of them.
Where polymorphism often comes into play is when you create a method that takes a data type with many possible subclasses. For example, imagine that we have a function that opens the zoo and prints the time. As input, it takes a Number
as an input parameter.
public void openZoo(Number time) {}
Now, we want the function to add O'clock
to the end of output if the value is a whole number type, such as an Integer
; otherwise, it just prints the value.
public void openZoo(Number time) { if (time instanceof Integer) System.out.print((Integer)time + " O'clock"); else System.out.print(time); }
We now have a method that can intelligently handle both Integer
and other values. A good exercise left for the reader is to add checks for other numeric data types such as Short
, Long
, Double
, and so on.
Notice that we cast the Integer
value in this example. It is common to use casting with instanceof
when working with objects that can be various different types, since casting gives you access to fields available only in the more specific classes. It is considered a good coding practice to use the instanceof
operator prior to casting from one object to a narrower type.
instanceof
is used with classes and interfaces. Although it can be used with other high-level types, such as records, enums, and annotations, it is not common.
Invalid instanceof
One area the exam might try to trip you up on is using instanceof
with incompatible types. For example, Number
cannot possibly hold a String
value, so the following causes a compilation error:
public void openZoo(Number time) { if(time instanceof String) // DOES NOT COMPILE System.out.print(time); }
If the compiler can determine that a variable cannot possibly be cast to a specific class, it reports an error.
null and the instanceof operator
What happens if you call instanceof
on a null
variable? For the exam, you should know that calling instanceof
on the null