Wednesday, June 27, 2007

Chapter 3 - Operators and Assignments

Go to Home Page




Chapter 3: Operators and Assignments


Chapter Introduction

This chapter is an easy chapter to master. It is also an important one to know. Operators are a basic
building block from which Java expressions and statements are built. You should already be pretty
familiar with the use of many of the operators covered in this chapter. On the other hand, there may be
a handful of operators that you've seen before, but you are not quite familiar with. It's up to you to
identify which ones they are and firm up your knowledge of how they work. This is essential to doing
well on the exam. There are a number of operator-specific and operator-related questions. These are
some of the easier questions on the test. You should answer all of them correctly. If you don't learn
operators well, not only will you miss some of the operator-specific questions, you may also miss some
of the more complex questions that assume knowledge of basic operators.

This chapter reviews all of the Java operators and provides examples of their use. It covers operator
precedence and shows how it is used in expression evaluation. It also covers casting and conversion
and those situations where automatic type conversion comes into play. Read through this chapter and
fill in any gaps that you may have. The review questions and exam questions will let you know how well
you know this material and will give you an idea of how well you will do in operator-specific exam
questions.

Java Operators

Java's operators originate in C and C++. If you are a C or C++ programmer, I have good news and bad
news. The good news is that many of Java's operators have the same behavior as they do in C and
C++. The bad news is that some do not, and the ones that don't can trip you up on the exam. I don't
assume that you have a background in C or C++, but I hope that you are far enough in your Java
programming that most of the operators in Table 3.1 are familiar to you. Take the time now to go
through the table and check off the ones you are familiar with. Then highlight the ones that you need to
study. Pay careful attention to these operators when you work your way through this chapter.

Table 3.1: Operator Summary

Category Operator Example Result
Arithmetic + (Unary) +3 The int
value 3.
+ (Binary) 2 + 4 The value of
x is 6.
- (Unary) -x The sign of x
is changed.
-(Binary) 4 - 2 The value of
x is 2.
++
(Prefix)
x = 3
y = ++x
The value of
x is 4
and
the value of
y is 4.
++
(Postfix)
x = 3
y =
x++;
The value of
x is 4
and
the value of
y is 3.
--
(Prefix)
x = 3
y = --x
The value of
x is 2
and
the value of
y is 2.
--
(Postfix)
x = 3
y = x--
The value of
x is 2
and
the value of
- 33



y is 3.
* 4 * 3 12
/ 11 / 4 2
% 11 % 4 3
String + "ab" +
"cd"
"abcd"
Bitwise ~ ~3 -4
& 3 & 4 0
| 3 | 4 7
^ 5 | 4 4
Shift << 3 << 2 12
>> -6 >> 2 -2
>>> -6 >>>
2
1073741822
Comparison < 5 < 7 true
<= 5 <= 7 true
> 5 > 7 false
>= 5 >= 7 false
== 5 == 7 false
!= 5 != 7 true
instanceof "abc"
instanc
eof
String
true
Logical & true & false
false
| true | true
false
^ true ^ true
false
! !true false
&& true && false
false
|| true || true
false
Category Operator Example Result
Assignment = x = 5; The value of
x is 5.
+= x = 1;
x += 5;
The value of
x is 6.
-= x = 1;
x - =
5;
The value of
x is -4.
*= x = 1;
x *= 5;
The value of
x is 5.
/= int x =
1;
x /= 5;
The value of
x is 0.
%= x = 1;
x %= 5;
The value of
x is 1.
- 34



&= x = 1;
x &= 5;
The value of
x is 1.
|= x = 1;
x |= 5;
The value of
x is 5.
^= x = 1;
x ^= 5;
The value of
x is 4.
<<= x = 1;
x <<=
5;
The value of
x is 32.
>>= x = 1;
x >>=
5;
The value of
x is 0.
>>>= x = 1;
x >>>=
5;
The value of
x is 0.
Cast (type) double
d =
4.2;=
byte b=
(byte)
d;
The value of
b is 4.
Ternary ? : x = 1;
x = (x> 0)
? 5 :
10
The value of
x is 5.
Unary Arithmetic Operators

The arithmetic operators consist of both unary and binary operators. Unary operators perform
operations on a single operand. Binary operations perform operations on two operands. For example, in
the expression, -x, the - operator is used as a unary operator. In the expression, x-y, the - operator is
used as a binary operator.
The unary operators are used to increment, decrement, or change the sign of a value. The + unary
operator has no effect on the sign of a value. The - unary operator changes the sign of a value. Both
the + and - operators have subtle effects on byte, char, and short values. When the + or
operators are applied to a value of these types the value is first converted to an int value. The result of
the operation is an int value. This process, referred to as numeric promotion, is discussed further for
binary arithmetic operations, in the later section, "Numeric Promotion."
The ++ and -- operators are used to increment and decrement a value. For example, if x is 1 then ++x
results in the value of 2 being assigned to x. If x is 6 then --x results in the value 5of 5 being assigned
to x. The ++ operators may appear before the value (prefix) or after the value (postfix). Examples are:
++x (prefix)
x++ (postfix)
--x (prefix)
x-- (postfix)
If xis 4 in the above expressions, then the first two expressions result in 5 being assigned to x, and the
last two expressions result in 4 being assigned to x. Because the prefix and postfix forms of the
increment and decrement operators both result in the same value being assigned to x, you may wonder
what the difference is between the prefix and postfix forms. There is one significant difference between
the prefix and postfix forms, and there's a fair chance that you'll encounter it on the test. The difference
involves the use of prefix and postfix expressions in assignments. When a prefix expression is used in
an expression, the value that is returned is the value that is calculated after the prefix operator is
applied. When a postfix expression is used in an expression, the value that is returned is the value of
the expression before the postfix operator is applied. The following examples illustrate these rules:

x = 10;

y = ++x; // The value assigned to y is 11

- 35



x = 10;

y = x++; // The value assigned to y is 10

x = 10;

y = --x; // The value assigned to y is 9

x = 10;

y = x--; // The value assigned to y is 10

You can see the difference in the results returned by the prefix and postfix operators in the preceding
examples. If you want to make sure that the calculation is performed before returning a value, always
use the prefix operator.

Binary Arithmetic Operators

Now that you've looked at the unary arithmetic operators, we'll cover the binary arithmetic operators +
(addition), - (subtraction), * (multiplication), / (division), and % (modulo).

The binary arithmetic operators are fairly straightforward—they perform simple calculations on a pair of
numeric values. However, there are a few special cases that need to be considered:

.
When an operation is performed on operands of different types
.
When the result of an integer division must be rounded
.
Division by zero
.
Modulo operations
.
Operations that result in the throwing of runtime exceptions
.
Operations that result in overflow or underflow
We'll cover each of the above special cases in the following sections, showing how they apply to each
operator.

Numeric Promotion

When binary operations are applied to numeric arguments (integer and floating-point), numeric
promotion is performed before the operation takes place. The numeric promotion consists of converting
the values of the operands to a common type. The rules for this conversion are straightforward.

.
If one of the operands is a double, then the other is converted to a double.
.
Otherwise, if one of the operands is a float, then the other is converted to a float.
.
Otherwise, if one of the operands is a long, then the other is converted to a long.
.
Otherwise, both operands are converted to int values.
Make sure that you remember these rules. You won't be tested on the rules themselves, but you'll need
to know them to work through related questions. One thing that you probably will see on the test is +
operations involving a numeric value and a String value. These questions test your knowledge of the
difference between the arithmetic + operator and the String+ operator. The String+operator
results in the concatenation of two String objects. For example, "abc" + "def" results in
"abcdef". But what about, 10 + "0" or "2.4" + 2.5?
The rule that you should remember is that when one of the operands in a + operation is a String, then
the other operand is converted to a String. Therefore, 10 + "0" results in the String"100" and
"2.4" + 2.5 results in the String object "2.42.5". The other operand is converted to a Stringobject in one of two ways, depending on whether the operand is an object or a value of a primitive type.
If the other operand is an object, then its toString() method is invoked to convert it to a Stringobject. If the other operand is a value of a primitive type, then an object of the type's wrapper class is
created (see Chapter 9, "The java.lang Package") and the object's toString() method is invoked
to convert it to a String object.
- 36



Integer Division and Division by Zero

Java, like many other languages, supports division (/) operations on integer (long, int, short, char,
and byte) values. In order to return the result of operations like 4/3 as an integer value, it rounds
toward zero. This is the same as truncating the fractional part of the result. The following list provides
some examples of integer division.

.
10 / 3 results in
3
.
-10 / 3 results in -
3
.
10 / -3 results in -3
.
11 / 3 results in
3
.
-11 / 3 results in -
3
.
11 / -3 results in -3
In mathematics, division by zero is undefined. In Java, division by zero results in different values,
depending on whether the operation is performed on an integer value, a positive floating-point value, or
a negative floating-point value.
Division of an integer by zero results in the throwing of an ArithmeticException. Division of a
positive floating-point value by zero results in POSITIVE_INFINITY. Division of a negative floating
point value by zero results in NEGATIVE_INFINITY. Note that when the sign of zero is negative, such
as -0, the sign of the result is reversed. This only applies to floating point operations.

Modulo Operations

For many, the modulo operator %, also referred to as the remainder operator, is not as familiar as the
other binary mathematical operators. First of all, it has nothing to do with percentages. It is the
remainder that results when the first operand is divided by the second. That is, x % y is x - ((int)
(x/y)*y). Java, unlike C and C++, allows floating-point operands to be used with the %operator. The
results of using the % operator with floating-point operands are calculated in a similar manner. The
following list provides some examples of the % operator in action.

.
11 % 3 results in 2.
.
11 % -3 results in 2.
.
-11 % 3 results in -2.
.
-11 % -3 results in -2.
.
11.5 % 3.2 results in 1.8999999999999995. (that is, approximately 1.9)
.
11.5 % -3.2 results in 1.8999999999999995.
.
-11.5 % 3.2 results in -1.8999999999999995.
.
-11.5 % -3.2 results in -1.8999999999999995.
Note that if x is positive and y is not zero, x % y is positive. If x is negative and y is not zero, then x %
y is negative. If x is an integer value and yis zero, then x % y results in the throwing of an
ArithmeticException. If x is a floating-point value and yis zero, then x % y results in NaN (but no
exception is thrown).

Runtime Exceptions

The only runtime exception that occurs during arithmetic operations is the ArithmeticException.
This exception is never thrown in floating-point operations and only occurs in integer operations when
dividing by 0 or taking the remainder of a number by 0. Although you won't be tested on this fact
directly, remember it to help you to weed out bad answers in related questions.

Overflow and Underflow

A numeric overflow occurs when the result of a calculation is larger than the largest value that can be
represented by a type. A numeric underflow occurs when the result of a calculation is smaller than the
smallest value that can be represented by a type. Because arithmetic operations are performed using
numeric values of limited size, some operations result in overflow and underflow. You can determine if
an operation results in an overflow or underflow by calculating its result and determining whether the
result is too large or small to be represented using the number of bytes available to the type. In cases of
integer (but not floating point) overflow and underflow, the lower order bytes of the result that are
capable of fitting into the type are returned as the result of the operation. Figure 3.1 shows how this
occurs:
For example, consider the following program (see Listing 3.1):

- 37



Figure 3.1: How Java handles overflows and underflows.

Listing 3.1: Overflow.java—An Example of the Result of an Overflow Operation


class Overflow {
public static void main(String args[]) {
int n = 2000000000;
System.out.println(n * n);
}

}
The result displayed by this program is -1651507200, which is hardly the square of 2 billion. To
determine how this result is calculated, look at the arithmetic that takes place.

.
2,000,000,000 is represented as 01110111 00110101 10010100 00000000 in
binary form.
.
2,000,000,000 * 2,000,000,000 results in 4,000,000,000,000,000,000, which is
00110111 10000010 11011010 11001110 10011101 10010000 00000000
00000000 in binary form.
.
This overflows the 32-bit int type. Therefore, we only save the last 4 bytes (10011101
10010000 00000000 00000000) as the result.
.
The value of the last 4 bytes is the binary representation of the int value -1651507200.
The good news is that you won't see any questions that will ask you to calculate whether an operation
results in an overflow or underflow. However, there may be some answers to multiple choice questions
that say that an operation results in an overflow or underflow. By being familiar with how overflows and
underflows occur, you will be able to tell which answers are obviously true and which are used as
distractors.

Bitwise Operators

The bitwise operators, ~ (inversion), & (and), | (or), and ^ (exclusive-or) perform operations on integer
values. The ~ operator is a unary operator, and the others are binary operators. Figure 3.2 summarizes
how each operator performs its calculation.

- 38



Figure 3.2: How the bitwise operators work.
The ~ operator inverts the bits which make up the integer value. That is, 0 bits become 1 bits and 1 bits
become 0 bits. For example, ~3 yields the value -4. It is calculated as follows:

.
3 is represented as the binary int value 00000000 0000000000000000 00000011.
.
Inverting each of the bits yields 11111111 1111111111111111 11111100, which is the
bit pattern for -4 as an int value.
The &, |, and ^ operators calculate their results in a bit-by-bit fashion. That is, the nth bit of the result is
calculated using only the nth bit of each operand. These bit-level operations are performed as follows:

.
The & operator returns a 1 bit if the corresponding bits of its operands are both 1. It returns a
0 otherwise.
.
The | operator returns a 0 bit if the corresponding bits of its operands are both 0. It returns a
1 otherwise.
.
The ^ operator returns a 0 bit if the corresponding bits of its operand are both 0or both 1. It
returns a 1 otherwise.
Note
Numeric Promotion Numeric promotion is used with both unary and binary
bitwise operators. This means that byte, char, and short values are converted
to int values before a bitwise operator is applied. If a binary bitwise operator has
one long operand, the other operand is converted to a long value. The type of
the result of a bitwise operation is the type to which the operands have been
promoted.

Table 3.2 summarizes the operation of these operators.

Table 3.2: Binary Bitwise Operators

Operand 1 Operator Operand
2
Result
0 & 0 0
0 & 1 0
1 & 0 0
1 & 1 1
0 | 0 0
0 | 1 1
1 | 0 1
1 | 1 1
0 ^ 0 0
0 ^ 1 1
1 ^ 0 1
1 ^ 1 0
Let's consider the expressions 63 & 252, 63 | 252, and 63 ^ 252. To calculate the value of these
expressions, we first represent the int values 63 and 252 as bit patterns:
00000000 00000000 00000000 00111111 = 63
00000000 00000000 00000000 11111100 = 252

- 39



Because & returns a 1 bit if, and only if, the corresponding bit from each operand is 1, we calculate 63
& 252 to be 60 as follows:

00000000 00000000 00000000 00111111 = 63

00000000 00000000 00000000 11111100 = 252

00000000 00000000 00000000 00111100 = 60
Because | returns a 0 bit if and only if the corresponding bit from each operand is 0, we calculate 63 |
252 to be 255 as follows:

00000000 00000000 00000000 00111111 = 63

00000000 00000000 00000000 11111100 = 252

00000000 00000000 00000000 11111111 = 255
Because ^ returns a 0 bit if, and only if, the corresponding bit from each operand match, we calculate
63 | 252 to be 195 as follows:

00000000 00000000 00000000 00111111 = 63

00000000 00000000 00000000 11111100 = 252

00000000 00000000 00000000 11000011 = 195

The results of bitwise operations are easy to calculate after you've tried a few examples. The questions
at the end of this chapter will help you study them. You may see an exam question that requires you to
know how the bitwise operators work.

Note Java's Platform Independence Because Java is implemented using a platform-

independent virtual machine, bitwise operations always yield the same result,

even when run on machines that use radically different CPUs.

Shift Operators

The shift operators << (left shift), >> (right shift), and >>> (unsigned right shift) also work on the bit
level. All of these operators are binary operators. If you took the JDK 1.1 Programmer Certification
exam, you probably remember a few shift-related questions. Shift-related questions are not emphasized
as much on the JDK 1.2 exam. However, you may still encounter a question that involves shifting. With
a little bit of practice, you'll find that these operators are easy to use.
Numeric promotion is used with the shift operators. The left operand is promoted to an int if it is a
byte, char, or short value. Then the right operand is promoted in the same manner. Note that when
the left operand is an int, only the last 5 bits of the right operand are used to perform the shift. That's
because an int is a 32-bit value and can only be shifted 0 through 31 times. When the left operand is a
long value, only the last 6 bits of the right operand are used to perform the shift. Because long values
are 64-bit values, they only can be shifted 0 through 63 times.
The << operator causes the bits of the left operand to be shifted to the left, based on the value of the
right operand. The new bits that are used to fill in the shifted right bits have the value 0. Figure 3.3
illustrates the process of shifting left. Note that the leftmost bits shifted out of the operand are discarded.
The >> operator causes the bits of the left operand to be shifted to the right, based on the value of the
right operand. The bits that fill in the shifted left bits have the value of the leftmost bit (before the shift
operation). The >> operator is said to be a signed shift because it preserves the sign (positive or
negative) of the operand. Figure 3.4 illustrates how the signed right shift is performed. The right-most
bits that are shifted out of the operand are discarded.
The >>> operator is identical to the >> operator, except that the bits that fill in the shifted left bits have
the value of 0. The >>> operator is said to be an unsigned shift because it does not preserve the sign of
the operand. Figure 3.5 illustrates how the unsigned right shift is performed. The rightmost bits that are
shifted out of the operand are discarded.

- 40



Figure 3.3: The << (left shift) operator.

Figure 3.4: The >> (right shift) operator.
Figure 3.5: The >>> (unsigned right shift) operator.

Comparison Operators

The comparison operators are used to compare primitive values or object references. They are
organized into three subgroups: the relational operators, the equality operators, and the instanceof
operator. The relational operators are only defined for numeric values and the instanceof operator is
only defined for object references.

The Relational Operators

The four relational operators are < (less than), <= (less than or equals), > (greater than), and >=
(greater than or equals). These operators follow their mathematical definitions and produce a boolean
value as their result. However, you should note that any relational expression with the NaN value
evaluates to false.

The Equality Operators

The equality operators consist of == (is equal) and != (is not equal). These operators may be used with
the eight primitive types, as well as object references. They return a boolean value in each case. When
they are used with primitive values, the following rules apply:

.
Numeric values cannot be compared to boolean values. Such a comparison results in a
compilation error.
- 41



.
Numeric promotion takes place before numeric values are compared. This enables any
numeric value to be compared with any other numeric value.
Let's examine what happens in the following program (see Listing 3.2) as the result of the above rules.

Listing 3.2: EqualNumbers.java—Using the Equality Operators


class EqualValues {
public static void main(String args[]) {
byte b = 3;
int i = 5;
float f = 5.0f;
double d = 3.0;
System.out.println((b == d) == (i == f));
}

}
The computation of interest takes place as an argument to the println() method. The expression
(b==d) is evaluated. This results in the promotion of the byte value 3 to a double value. The ==
expression returns a value of true. The expression (i == f) is then evaluated. The int value of 5is
promoted to a float value and the == expression returns a value of true. This results in an
expression true == true as the argument to the println() method. A value of true is printed as
the result. (Note that the true value is converted to a String object by the println() method.)
When object references are compared, the == and != operators check to see if the objects being
compared are the same object instance, and not whether the objects have the same values. For
example, suppose objects A and B are both object of the same class and have exactly the same field
values. If these objects are distinct (that is they are located in different areas of memory), then A == B
evaluates to false, and A != B evaluates to true. Figure 3.6 summarizes the process used in
evaluating expressions that use the equality operators.
Because String objects of identical values may be created during a program's execution, you must be
careful not to compare the values of these objects using the == operator. For example, the following
program (see Listing 3.3) displays a value of false when comparing two String objects with the
same values.

Listing 3.3: EqualStrings1.java—An Example That Uses the == Operator to Compare String Objects
class EqualStrings1 {

public static void main(String args[]) {
String s = "ab";
String s1 = s + "cd";
String s2 = "abcd";
System.out.println(s1);
System.out.println(s2);

- 42



System.out.println(s1 == s2);
}

}
Figure 3.6: Comparing object references.
The equals() method is defined by the Object class as a means to tell whether two objects have the
same value. It is overridden by subclasses of Object, such as String, to provide class-specific value
comparisons. Let's use the equals() method to compare the values of the two String objects from
Listing 3.3. The following program (Listing 3.4) displays a value of true when comparing the two
String objects, referenced by s1 and s2.

Listing 3.4: EqualStrings2.java—An Example That Uses the Equals() Method to Compare StringObjects


class EqualStrings2 {

public static void main(String args[]) {
String s = "ab";
String s1 = s + "cd";
String s2 = "abcd";
System.out.println(s1);
System.out.println(s2);
System.out.println(s1.equals(s2));

}

}
The instanceofOperator

The instanceof operator is a binary operator that determines whether an object reference (the left
operand) is an instance of the class, interface, or array type specified by the right operand. The
instanceof operator cannot be used with primitive types (this results in a compilation error).

- 43



The instanceof operator returns a boolean value of true if the left operand references a non-null

object of class C (or array of type T), so that at least one of the following conditions holds.

.
The right operand is a class name C' and C is a subclass of C'.
.
The right operand is an interface name I, and C implements I.
.
The right operand is an array of type T', the left operand is an array of type T, and T is a
subclass or subinterface of T' or equal to T'.
The instanceof operator returns false if none of the above conditions are met or if the left operand
is null.
The following program (see Listing 3.5) illustrates the use of the instanceof operator.

Listing 3.5: Instance.java—Using the Instanceof Operator to Determine an Object's Runtime Type


import java.util.*;

class Instance {

public static void main(String args[]) {
String s = "abcd";
Vector v = new Vector();
v.add(s);
Object o = v.elementAt(0);
System.out.println(s instanceof String);
System.out.println(s instanceof Object);
System.out.println(o instanceof String);
System.out.println(o instanceof Object);
System.out.println(o instanceof Vector);

}

}
When you run the program, it produces the following results:
true
true
true
true
false

The first two output lines reflect the fact that s is a String and therefore an Object (because Stringis a subclass of Object). The third output line displays a value of true even though o is declared to be
of type Object. How is this so? That's because the object assigned to o is the String object that was
added to Vectorv. The fourth and fifth output lines result from the fact that a String object is an
Object object but not a Vector object.

- 44



Logical Operators

Java supports two groups of logical operators, the boolean operators ! (not), & (and), | (or), and
^
(exclusive-or), and the logical short-circuit operators && (short-circuit and) and || (short-circuit or). All of
these operators are restricted to boolean operands.
The ! operator performs logical negation. Its operation is simply described:


.
!x results in false if x is true.
.
!x results in true if x is false.
The &, |, and ^ operators operate in the same manner that the bitwise operators do when applied to
each bit. This operation is described in Table 3.3.
Table 3.3: The Boolean Operators &, |, and ^

Operand 1 Operator Operand
2
Result
false & false false
false & true false
true & false false
true & true true
false | false false
false | true true
true | false true
true | true true
false ^ false false
false ^ true true
true ^ false true
true ^ true false
The logical short-circuit operators, && and ||, produce the same logical result as & and |, but differ in
the way they are evaluated. Given an expression x & y, evaluation proceeds in the following order:

1. Evaluate x.
2. Evaluate y.
3. Apply Table 3.3 to determine the result of x & y.
However, the expression x && y is evaluated in the following manner:
1. Evaluate x.
2. If x is false, return false.
3. Otherwise, if x is true evaluate y.
4. Return the value of y.
The && operator is called a short-circuit operator because it skips the evaluation of the second operand,
if the first operand is evaluated as false.
The || operator also operates in a short-circuit fashion. The expression x || y is evaluated as
follows:
1. Evaluate x.
2. If x is true return true.
3. Otherwise, if x is false evaluate y.
4. Return the value of y.
If the first operand of || is true then the evaluation of the second operand is skipped.
The following program (see Listing 3.6) illustrates the results of using the &, |, &&, and || operators.
LogicalListing 3.6: Logical.java—Using the Boolean and Short-Circuit Operators

class Logical {
static boolean sideEffect(boolean b) {
System.out.print("Side effect! ");
return b;

- 45



}

public static void main(String args[]) {
boolean t = true;
boolean f = false;
System.out.println(false & sideEffect(true));
System.out.println(false && sideEffect(true));
System.out.println(true | sideEffect(true));
System.out.println(true || sideEffect(true));

}

}
When you run the program, it produces the following results:

Side effect! false

false

Side effect! true

true

Logical Operators

Java supports two groups of logical operators, the boolean operators ! (not), & (and), | (or), and
^
(exclusive-or), and the logical short-circuit operators && (short-circuit and) and || (short-circuit or). All of
these operators are restricted to boolean operands.
The ! operator performs logical negation. Its operation is simply described:


.
!x results in false if x is true.
.
!x results in true if x is false.
The &, |, and ^ operators operate in the same manner that the bitwise operators do when applied to
each bit. This operation is described in Table 3.3.
Table 3.3: The Boolean Operators &, |, and ^

Operand 1 Operator Operand
2
Result
false & false false
false & true false
true & false false
true & true true
false | false false
false | true true
true | false true
true | true true
false ^ false false
false ^ true true
true ^ false true
true ^ true false
- 46



The logical short-circuit operators, && and ||, produce the same logical result as & and |, but differ in
the way they are evaluated. Given an expression x & y, evaluation proceeds in the following order:

1. Evaluate x.
2. Evaluate y.
3. Apply Table 3.3 to determine the result of x & y.
However, the expression x && y is evaluated in the following manner:
1. Evaluate x.
2. If x is false, return false.
3. Otherwise, if x is true evaluate y.
4. Return the value of y.
The && operator is called a short-circuit operator because it skips the evaluation of the second operand,
if the first operand is evaluated as false.
The || operator also operates in a short-circuit fashion. The expression x || y is evaluated as
follows:
1. Evaluate x.
2. If x is true return true.
3. Otherwise, if x is false evaluate y.
4. Return the value of y.
If the first operand of || is true then the evaluation of the second operand is skipped.
The following program (see Listing 3.6) illustrates the results of using the &, |, &&, and || operators.
LogicalListing 3.6: Logical.java—Using the Boolean and Short-Circuit Operators

class Logical {

static boolean sideEffect(boolean b) {
System.out.print("Side effect! ");
return b;

}

public static void main(String args[]) {
boolean t = true;
boolean f = false;
System.out.println(false & sideEffect(true));
System.out.println(false && sideEffect(true));
System.out.println(true | sideEffect(true));
System.out.println(true || sideEffect(true));

}

}
When you run the program, it produces the following results:
Side effect! false
false

- 47



Side effect! true
true

Assignment Operators

Java provides a full suite of assignment operators, including the basic = assignment operator and the C
op= style operators where op is a binary arithmetic operator. These operators are as follows:

.
x = y The variable x is assigned the value of y.
.
x += y The variable x is assigned the value of x + y.
.
x -= y The variable x is assigned the value of x - y.
.
x *= y The variable x is assigned the value of x * y.
.
x /= y The variable x is assigned the value of x / y.
.
x %= y The variable x is assigned the value of x % y.
.
x &= y The variable x is assigned the value of x & y.
.
x |= y The variable x is assigned the value of x | y.
.
x ^= y The variable x is assigned the value of x ^ y.
.
x <<= y The variable x is assigned the value of x <<= y.
.
x >>= y The variable x is assigned the value of x >>= y.
.
x >>>= y The variable x is assigned the value of x >>>= y.
With the exception of the = simple assignment operator and the += operator, all of the other above
operators are used with primitive types. Note that the &, |, and ^ operators can be used with both
Boolean and numeric arguments. The += operator may also be used with String objects.
The assignment operators of the form op= cast their result to the type of the left operand. For example,
if b is of type byte, b += 3, assigns (byte) (b + 3) to b. This is important because the value of b
is promoted to an int value before the addition takes place. The following program (Listing 3.7)
compiles without a compilation error:
Listing 3.7: Cast1.java—Casting and the += Operator
class Cast1 {

public static void main(String args[]) {
byte b = 0;
b += 3;
System.out.println(b);

}

}
Unlike the op= operators, the = operator does not perform an implicit cast. The following program
(Listing 3.8) results in a compilation error because casting is required to assign an int value to a bytevalue.

Listing 3.8: Cast2.java—Casting and the = Operator
class Cast2
{
public static void main(String args[])
{
byte b = 0;


- 48



b = b + 3;

System.out.println(b);
}

}
When the simple assignment operator is used with object references, a few rules apply:

.
If the type of the left operand is a class C, then the type of the right operand must be a
subclass of C or the null value.
.
If the type of the left operand is an interface I, the type of the right operand must be a
subinterface of I, or a class that implements I, or the null value.
The following section shows how casting can be used to change the type associated with the right
operand before an assignment is made.


There are two more points to cover about the assignment operator:

.
The value (and type) returned by an assignment is the value (and type) assigned to the left
operand.
.
The simple assignment operator is right associative. This means that a = b = c is
evaluated as a = (b = c). All other operators are left associative. For example, a + b +
c is evaluated as (a + b) + c.
The following program (see Listing 3.9) illustrates the above two rules. The statement i = j = k = lis evaluated as follows:

1.
The value of l (4) is assigned to k.
2.
The value of k = l (4) is assgined to j.
3.
The value of j = k = l (4) is assigned to i.
Listing 3.9: Assign.java—Associativity and the = Operator


class Assign {

public static void main(String args[]) {
int i = 1;
int j = 2;
int k = 3;
int l = 4;
i = j = k = l;
System.out.println(i);
System.out.println(j);
System.out.println(k);
System.out.println(l);

}
}

- 49



The Cast Operator

The cast operator (type) is used to convert numeric values from one numeric type to another or to
change an object reference to a compatible type.


Widening and Narrowing Conversions

A widening conversion is a conversion from a smaller numeric type to a larger numeric type. An
example of a widening conversion is when a byte value is promoted to an int value. A narrowing
conversion is a conversion from a larger numeric type to a smaller numeric type. A conversion from a
long value to a short value would be an example of a narrowing conversion. Narrowing conversions
require the use of the cast operator.


Casting can be used to enable numeric conversions that would normally be disallowed by the compiler.
For example, the following program (see Listing 3.10) assigns the value 123 to the b variable. Without
the (byte) cast operator, the compiler would generate an error message.

Listing 3.10: Cast3.java—Casting Numeric Values
class Cast3 {

public static void main(String args[]) {
double d = 123.456;
byte b;
b = (byte) d;
System.out.println(b);

}

}
When casting is used with object references, the following rules apply:

1.
A reference to any object can be cast into a reference to an object of class Object.
2.
A reference to an object can be cast into a reference to an object of class C', if the actual
class of the object is a subclass of C'.
3.
A reference to an object can be cast into a reference to an object of interface I, if the actual
class of the object implements I, if the object is of interface type I' and I' is a
subinterface of I, or if the object is an array type and I is the Cloneable interface.
4.
A reference to an object can be cast a reference to an object of an array type (with element
reference type T), if the object is of an array type (with element reference type T') such
that T' can be cast into T.
Let's examine each of the above rules.
The first rule is pretty simple. Any object reference can be cast to an Object object using the
(Object) cast operator.


- 50



Figure 3.7 summarizes the second rule. When an object is created, it is an object of some specific class
(referred to as the actual class in the rule). The object may be subsequently referenced by a superclass
reference or an interface reference. For example, a String object may be created and then referenced
as an Object object. Casting can be used to change the object's reference back to its original class
(for example, String).


Figure 3.7: Casting between classes.
The third rule covers casting to interfaces. If the actual class of an object implements the interface, the
object can be cast to that interface. For example, a Vector object can be cast to a List object, and a
List object can be cast to a Collection object. Because the array type implements the Cloneable
interface, any array can be cast into a Cloneable object.
Casting to array types is more complicated. In order to cast to an object reference to an array type
reference, the object must be an array of a component type that is compatible with the component type
of the array type reference. Figure 3.8 summarizes casting to array types.
As an example of object type casting, consider the following program (Listing 3.11). Without the
(String) cast operator, the result returned by v.elementAt(0) is an object of the Object class.
The compiler recognizes this inconsistency and generates an error message. When the (String) cast
operator is used, the compiler recognizes that you are casting the reference to an Object object into a
String object and proceeds with the compilation.

Listing 3.11: Cast4.java—Casting Object References


import java.util.*;

class Cast4 {

public static void main(String args[]) {
String s1 = "abc";
String s2 = "def";
Vector v = new Vector();
v.add(s1);
s2 = (String) v.elementAt(0);
System.out.println(s2);

- 51



}
}

The Ternary Operator

The ternary operator ? :, also referred to as the conditional operator, has three operands and takes the
following form:

operand1 ? operand2 : operand3
Figure 3.8: Casting to array types.

The first operand must be of boolean type. The first operand is evaluated and if true, the value of the
second operand is returned. In this case, evaluation of the third operand does not take place. If the
value of the first operand is false, evaluation of the second operand is skipped, and the value of the third
operand is returned. The Java compiler requires that the second and third operands be promotable
(numeric values) or castable (object references) to a common type.
For example, the program shown in Listing 3.12 produces the output 0xx3xx6xx9.

Listing 3.12: Ternary.java—Using the Ternary Operator
class Ternary {
public static void main(String args[]) {
for(int i=0;i<10;++i)
System.out.print((i%3==0)? ("" + i) : "x");
}

}
Operator Precedence and Order of Evaluation

The order in which expressions are evaluated determines the values they produce. In Java, the
operands of an expression are evaluated in a left-to-right fashion before any operations are performed.
The only exceptions to this are operations involving the logical short-circuit operators && and || and the
ternary operator. After evaluating the operands of an expression, the operators are applied according to
operator precedence and associativity. All binary operators are left associative except the = assignment
operator. Parentheses are used to alter the effects of precedence and associativity.
Figure 3.9 shows Java's operator precedence hierarchy. Operators at the top of the hierarchy take
precedence over lower level operators in the evaluation of an expression. Operators at the same level
are evaluated in the order they appear in an expression, according to their associativity.

- 52



Figure 3.9: Java's operator precedence hierarchy.
Use Figure 3.9 to evaluate a complex expression. Consider the program shown in Listing 3.13. It
displays the value abc9.

Listing 3.13: Precedence.java—Using the Operator Precedence to Evaluate Complex Expressions
class Precedence {

public static void main(String args[]) {
String s = "abc";
int x = 10;
boolean b = false;
s = s += x = x++ + 1 - 2 * 3 +

((Object) s instanceof String ? 4 << 5 / 6 & ++x:
7 ^ 8 % --x) | 9;
System.out.println(s);
}

}
The highest precedence operator is the postfix ++ operator. This increments the value of x to 11 but
returns the value of 10. Our expression reduces to

s = s += x = 10 + 1 - 2 * 3 + ((Object) s instanceof String ? 4 << 5 / 6 & ++x:

- 53



7 ^ 8 % --x) | 9;
Now the highest precedence operators is *. Applying this operator, reduce the expression to
s = s += x = 10 + 1 - 6 +
((Object) s instanceof String ? 4 << 5 / 6

& ++x: 7 ^ 8 % --x) | 9;
The highest precedence operators becomes the + and - operators. Applying these operators enables
us to reduce the expression to

s = s += x = 5 + ((Object) s instanceof String ? 4 << 5 / 6 & ++x:
7 ^ 8 % --x) | 9;

We must now evaluate the expression
(Object) s instanceof String ? 4 << 5 / 6 & ++x: 7 ^ 8 % --
x
and then plug it back in to the overall expression. Within this expression the (Object) cast operator has
the highest precedence. This causes s to be cast to an object of the Object class. (However,
s
remains fundamentally a String object.) We'll simplify the expression to


s instanceof String ? 4 << 5 / 6 & ++x: 7 ^ 8 % --
x
The ternary operator evaluates the operand to the left of the ? before selecting which operand 4 <<
5
/ 6 & ++x or 7 ^ 8 % --x to evaluate next. The expression s instanceof String evaluates to
true, and the overall expression simplifies to


4 << 5 / 6 & ++
x
The ++ operator is evaluated next. Because the value of xis now 11, it is incremented to 12 and the
expression simplifies to


4 << 5 / 6 & 12
The / is then evaluated, followed by << and then &. The expression is evaluated as follows:


4 << 0 & 12
4 & 12


Plugging this result back into the expression, you now have


s = s += x = 5 + 4 | 9;
Because + has a higher precedence than | the expression evaluates to
s = s += x = 9 | 9;


and then to


s = s += x = 9;
The value 9 is then assigned to x leaving
s = s += 9;


The value of s becomes "abc9", and the expression simplifies to
s = "abc9"
;


The above example is much more complex than any you'll see in the exam. If you can work your way
through this example, you should be able to tackle any exam question.


Chapter Summary

This chapter reviewed all of the Java operators and provided examples of their use. It covered operator
precedence and showed how it is used in expression evaluation. It also covered important points related
to casting and numeric promotion. You should now be prepared to test your knowledge of these
subjects. The following review questions and exam questions will let you know how well you understand
this material and will give you an idea of how you'll do on operator-specific exam questions. They'll also
indicate which material you need to study further.

Key Terms

.. Operator
.. Operand
- 54



.
Expression
.
Unary operator
.
Binary operator
.
Prefix operator
.
Postfix operator
.
Ternary operator
.
Numeric promotion
.
Casting
.
Overflow
.
Underflow
.
Precedence
.
Associativity
.
Order of evaluation
Review Questions

1.
What is the % operator?
2.
What is the difference between the prefix and postfix forms of the ++ operator?
3.
What are the legal operands of the instanceof operator?
4.
What is the difference between the Boolean & operator and the && operator?
5.
What is the difference between the >> and >>> operators?
6.
How is it possible for two String objects with identical values not to be equal under the
== operator?
7.
Is &&= a valid Java operator?
8.
Is the ternary operator written x : y ? z or x ? y : z ?
9.
Can a double value be cast to a byte?
10. Can a Byte object be cast to a double value?
11. Which arithmetic operations can result in the throwing of an ArithmeticException?
12. How is rounding performed under integer division?
13. What happens when you add a double value to a String?
14. How does Java handle integer overflows and underflows?
15. What factors determine the order of evaluation of an expression?
16. What is numeric promotion?
17. What is casting?
18. When can an object reference be cast to an interface reference?
19. What are order of precedence and associativity, and how are they used?
20. Which Java operator is right associative?
Exam Questions

1.
What is the value of 111 % 13?
A.
3
B.
5
C.
7
D.
9
2.
What is the value of 9 + 8 % 7 + 6?
A.
17
- 55



B. 16
C. 13
D. 4
3. What is the value of y after execution of the following statements?
4. int x = 5;
5. int y = 4;
y = x++
;
A. 4
B. 5
C. 6
D. 7
6. What is the value returned by "abcd" instanceof Object?
A. "abcd"
B. true
C. false
D. String
7. What is the value of 8 | 9 & 10 ^ 11?
A. 8
B. 9
C. 10
D. 11
8. What is the output displayed by the following program?
9. class Question {
10. public static void main(String[] args) {
11. int n = 7;
12. n <<= 3;
13. n = n & n + 1 | n + 2 ^ n + 3;
14. n >>= 2;
15. System.out.println(n);
16.
}
}
A. 0
B. -1
C. 14
D. 64
17. What is the value of -31 >>> 5 >> 5 >>> 5 >> 5 >>> 5 >> 5?
A. NaN
B. -1
C. 3
D. 1024
18. What is the value displayed by the following program?
19. class Question {
20. public static void main(String[] args) {
21. int x = 0;
22. boolean b1, b2, b3, b4;
23. b1 = b2 = b3 = b4 = true;
24. x = (b1 | b2 & b3 ^ b4) ? x++ : --x;
25. System.out.println(x);
26.
}
}
A. -1
- 56



B. 0
C. 1
D. 2
27. What line of output is displayed by the following program?
28. class Question {
29. static boolean sideEffect(boolean b) {
30. System.out.print(" side effect ");
31. return b;
32. }
33. public static void main(String[] args) {
34. boolean b1 = true;
35. boolean b2 = false;
36. if(b2 & sideEffect(b1)) System.out.println(1);
37. else if(b1 | sideEffect(b2)) System.out.println(2);
38.
}
}
A. 1
B. 2
C. side effect 1
D. side effect 2
E. side effect side effect 1
F. side effect side effect 2
39. What is the output displayed by the following program?
40. class Question {
41. public static void main(String[] args) {
42. String s1 = "ab";
43. String s2 = "abcd";
44. String s3 = "cd";
45. String s4 = s1 + s3;
46. s1 = s4;
47. System.out.print("s1 "+((s1 == s2)? "==" : "!=")+" s2");
48.
}
}
A. s1 == s2
B. s1 != s2
C. s1
D. s1 == "abcd"
49. Which statement (exactly one) is true about the following program?
50. class Question {
51. public static void main(String[] args) {
52. double d1 = 1.0;
53. double d2 = 0.0;
54. byte b = 1;
55. d1 = d1 / d2;
56. b = (byte) d1;
57. System.out.print(b);
- 57



58. }
}

A.
It results in the throwing of an ArithmeticException.
B.
It results in the throwing of a DivideByZeroException.
C.
It displays the value 1.5.
D.
It displays the value -1.
59. What is the result of the expression 5.4 + "3.2"?
A. The double value 8.6.
B. The String "8.6".
C. The long value 8.
D. The String "5.43.2".
60. What is the result of the following program?
61. class Question {
62. public static void main(String[] args) {
63. int i = 7;
64. int j = 8;
65. int n = (i | j) % (i & j);
66. System.out.print(n);
67. }
}

A.
0
B.
15
C. An ArithmeticException is thrown.
D.
-15
68. Suppose that classes X and Y are subclasses of Z and Z implements the W interface.
Which of the following are true?
A.
A reference to an object of class X can be cast to a reference to an object
of class Y.
B.
A reference to an object of class Y can be cast to a reference to an object
of class X.
C.
A reference to an object of class X can be cast to a reference to an object
of class Z.
D.
A reference to an object of class Y can be cast to a reference to an object
of class Z.
E.
A reference to an object of class X can be cast to a reference to an object
of interface W.
F.
A reference to an object of class Y can be cast to a reference to an object
of interface W.
G.
A reference to an object of class Z can be cast to a reference to an object
of interface W.
69. Which of the following are true?
A.
A reference to an array can be cast to a reference to an Object.
B.
A reference to an array can be cast to a reference to a Cloneable.
C.
A reference to an array can be cast to a reference to a String.
D.
None of the above.
Answers to Review Questions

1.
It is referred to as the modulo or remainder operator. It returns the remainder of dividing
the first operand by the second operand.
2.
The prefix form performs the increment operation and returns the value of the increment
operation. The postfix form returns the current value all of the expression and then
performs the increment operation on that value.
3.
The left operand is an object reference or null value and the right operand is a class,
interface, or array type.
- 58



4.
If an expression involving the Boolean & operator is evaluated, both operands are
evaluated. Then the & operator is applied to the operand. When an expression involving
the && operator is evaluated, the first operand is evaluated. If the first operand returns a
value of true then the second operand is evaluated. The && operator is then applied to
the first and second operands. If the first operand evaluates to false, the evaluation of
the second operand is skipped.
5.
The >> operator carries the sign bit when shifting right. The >>> zero-fills bits that have
been shifted out.
6.
The == operator compares two objects to determine if they are the same object in
memory. It is possible for two String objects to have the same value, but be located in
different areas of memory.
7.
No, it is not.
8.
It is written x ? y : z.
9.
Yes, a double value can be cast to a byte.
10. No, an object cannot be cast to a primitive value.
11. Integer / and % can result in the throwing of an ArithmeticException.
12. The fractional part of the result is truncated. This is known as rounding toward zero.
13. The result is a String object.
14. It uses those low order bytes of the result that can fit into the size of the type allowed by
the operation.
15. The order of the evaluation of an expression is determined by the use of parentheses,
the operator precedence, and the operator associativity.
16. Numeric promotion is the conversion of a smaller numeric type to a larger numeric type,
so that integer and floating-point operations may take place. In numerical promotion,
byte, char, and short values are converted to int values. The int values are also
converted to long values, if necessary. The long and float values are converted to
double values, as required.
17. There are two types of casting, casting between primitive numeric types and casting
between object references. Casting between numeric types is used to convert larger
values, such as double values, to smaller values, such as byte values. Casting
between object references is used to refer to an object by a compatible class, interface,
or array type reference.
18. An object reference can be cast to an interface reference when the object implements
the referenced interface.
19. Order of precedence determines the order in which operators are evaluated in
expressions. Associativity determines whether an expression is evaluated left-to-right or
right-to-left.
20. The = operator is right associative.
Answers to Exam Questions

1.
C. 111 = 8 * 13 + 7.
2.
B. Order of precedence requires that the expression be evaluated as (9 + (8 % 7) +
6).
3.
B. The postfix operator returns the value of x before incrementing x.
4.
B. The String"abcd" is an instance of Object so the value of true is returned.
5.
D. Order of precedence requires the expression to be evaluated as (8 | ((9 & 10)
^ 11)).
6.
C. The variable n takes on the values 7, 56, 57, and then 14.
7.
C. Use the process of elimination to answer this question. The expression returns a valid
integer result, so answer A is eliminated. Because the first operation is an unsigned right
shift, the final value of the expression must be non-negative. This rules out answer B.
Because the original 32-bit value is shifted right 30 times, it would be impossible to
produce a number as large as 1024. This rules out answer D. The only answer left is
answer C.
8.
B. From the ternary expression, the value of xmust either be 0or -1. Because (b1 |
b2 & b3 ^ b4) evaluates as (b1 | (b2 & (b3 ^ b4)), the answer is 0.
- 59



9.
F. Because we are not using the logical short-circuit operators, the sideEffect()
method is invoked in both cases, resulting in " side effect side effect 2"
being displayed.
10. B. Because s1 and s2 refer to different objects, s1 != s2 is true.
11. D. Floating-point operations do not throw exceptions. This eliminates answers A and B.
It would be impossible for a byte value to be displayed as 1.5. The only answer left is
D.
12. D. The floating point value is converted to a String and is then appended to "3.2".
13. C. An ArithmeticException is thrown as the result of taking the remainder of a
number by 0.
14. C through G. References to X and Y objects can be cast to Z and W objects. References
to Z objects can be cast to W objects. However, references to X and Y objects may not
be cast to each other.
15. A and B. A and B hold for all array types. An array may never be cast to a String.

Go to Home Page

No comments: