3 Operators and Assignments

3.1

(a)

A value of type char can be assigned to a variable of type int. An implicit widening conversion will convert the value to an int.

3.2

(d)

An assignment statement is an expression statement. The value of the expression statement is the value of the expression on the right hand side. Since the assignment operator is right associative, the statement a = b = c = 20 is evaluated as follows: (a = (b = (c = 20))). This results in the value 20 being assigned to variable c, then the same value being assigned to variable b and finally to variable a. The program will compile correctly and display 20 when run.

3.3

(c)

Strings are objects. The variables a, b, and c are references that can denote such objects. Assigning to a reference only changes the reference value. It does not create a copy of the source object or change the object denoted by the old reference value in the destination reference. In other words, assignment to references only affects which object the destination reference denotes. The reference value of the "cat" object is first assigned to variable a, then to variable b, and later to variable c. The program prints the string denoted by the variable c, which is "cat".

3.4

(a), (d), and (e)

A binary expression with any floating-point operand will be evaluated using floating-point arithmetic. Expressions such as 2/3, where both operands are integers, will use integer arithmetic and evaluate to an integer value.

3.5

(b)

The / operator has higher precedence than the + operator. This means that the expression is evaluated as ((1/2) + (3/2) + 0.1). The associativity of the binary operators is from left to right, giving (((1/2) + (3/2)) + 0.1). Integer division results in ((0 + 1) + 0.1) which evaluates to 1.1.

3.6

(d)

0x10 is a hexadecimal literal equivalent to the decimal value 16. 10 is a decimal literal. 010 is an octal literal equivalent to the decimal value 8. The println() method will print the sum of these values, which is 34, in decimal form.

3.7

(b), (c), and (f)

The unary + and - operators with right-to-left associativity are used in the valid expressions (b), (c), and (f). Expression (a) tries to use a nonexistent unary - operator with left-to-right associativity, expression (d) tries to use a decrement operator (--) on an expression that does not resolve to a variable, and expression (e) tries to use a nonexistent unary * operator.

3.8

(b)

The expression evaluates to ?6. The whole expression is evaluated as (((-(-1)) - ((3 * 10) / 5)) - 1) according to the precedence and associativity rules.

3.9

(a), (b), (d), and (e)

In (a) the conditions for implicit narrowing conversion are fulfilled: the source is a constant expression of type int, the destination type is of type short, the value of the source (12) is in the range of the destination type. The assignments in (b), (d), and (e) are valid, since the source type is narrower than the target type and an implicit widening conversion will be applied. The expression (c) is not valid. Values of type boolean cannot be converted to other types.

3.10

(a), (c), and (d)

The left associativity of the + operator makes the evaluation of (1 + 2 + "3") proceed as follows: (1 + 2) + "3" 3 + "3" "33". Evaluation of the expression ("1" + 2 + 3), however, will proceed as follows: ("1" + 2) + 3 "12" + 3 "123". (4 + 1.0f) evaluates as 4.0f + 1.0f 5.0f and (10/9) performs integer division, resulting in the value 1. The operand 'a' in the expression ('a' + 1) will be promoted to int, and the resulting value will be of type int.

3.11

(d)

The expression ++k + k++ + + k is evaluated as ((++k) + (k++)) + (+k) ((2) + (2) + (3)), resulting in the value 7.

3.12

(d)

The types char and int are both integral. A char value can be assigned to an int variable since the int type is wider than the char type and an implicit widening conversion will be done. An int type cannot be assigned to a char variable because the char type is narrower than the int type. The compiler will report an error about a possible loss of precision in the line labeled (4).

3.13

(c)

Variables of type byte can store values in the range ?128 to 127. The expression on the right-hand side of the first assignment is the int literal 128. Had this literal been in the range of the byte type, an implicit narrowing conversion would have to be applied during assignment to convert it to a byte value. Since 128 is outside the valid range of type byte, the compiler will not compile the code.

3.14

(a)

First, the expression ++i is evaluated, resulting in the value 2, Now the variable i also has the value 2. The target of the assignment is now determined to be the element array[2]. Evaluation of the right-hand expression, --i, results in the value 1. The variable i now has the value 1. The value of the right-hand expression 1 is then assigned to the array element array[2], resulting in the array contents to become {4, 8, 1}. The program sums these values and prints 13.

3.15

(a) and (c)

The expression (4 <= 4) is true. The null literal can be compared, so (null != null) yields false.

3.16

(c) and (e)

The remainder operator is not limited to integral values, but can also be applied to floating-point operands. Identifiers in Java are case sensitive. Operators *, /, and % have the same level of precedence. Type short has the range -32768 to +32767 inclusive. (+15) is a legal expression using the unary + operator.

3.17

(a), (c), and (e)

The != and ^ operators, when used on boolean operands, will return true if and only if one operand is true, and false otherwise. This means that d and e in the program will always be assigned the same value, given any combination of truth values in a and b. The program will, therefore, print true four times.

3.18

(b)

The element referenced by a[i] is determined based on the current value of i, which is zero, that is, the element a[0]. The expression i = 9 will evaluate to the value 9, which will be assigned to the variable i. The value 9 is also assigned to the array element a[0]. After the execution of the statement, the variable i will contain the value 9, and the array a will contain the values 9 and 6. The program will print 9 9 6 when run.

3.19

(c) and (d)

Unlike the & and | operators, the && and || operators short-circuit the evaluation of their operands if the result of the operation can be determined from the value of the first operand. The second operand of the || operator in the program is never evaluated because of short-circuiting. All the operands of the other operators are evaluated. Variable i ends up with a value of 3, which is the first digit printed, and j ends up with a value of 1, which is the second digit printed.

3.20

(b) and (f)

The method test() will print out its second argument if the results of performing a signed and an unsigned 1-bit right shift on its first argument differ. The only difference between these operations is that when performing a signed shift, the leftmost bit will retain its state, rather than being assigned the bit value 0. The operational difference will, therefore, only be apparent when applied on values where the value of the leftmost bit is 1. Of the values being passed to the method test(), only the result of the expression 1<<31 (i.e., 1000 ... 0000) and the value -1 (1111 ... 1111) have the left-most bit set.

3.21

(b) and (g)

Java has the operators >> and >>> to perform signed and unsigned right shifts. For left shifts there is no difference between shifting signed and unsigned values. Java, therefore, only has one left-shift operator, which is <<. <<< is not an operator in Java. Java has the boolean AND compound assignment operator &=, but &&= is not an operator in Java.

3.22

(b), (c), (d), and (e)

All the expressions will return the same result. All expressions will accommodate negative values, and x can be any value of type int. However, expression (a) will not assign the result back to the variable x.

3.23

(a), (c), and (d)

The logical complement operator (!) cannot be used as an integer bitwise operator, and the bitwise complement operator (~) cannot be used as a boolean logical operator.

3.24

(b), (c), and (e)

All the values of the expressions on the right-hand side of the assignments are implicitly promoted to type int. For expression (b) this works, since the target type is also int. The compound assignment operators in expressions (c) and (e) ensure that an implicit narrowing conversion makes the result fit back in the target variable. Expressions (a) and (d) are simply invalid, since the type of expression on the right-hand side of the assignment operator is not compatible with the type of the target variable on the left-hand side.

3.25

(b)

Evaluation of the actual parameter i++ yields 0, and increments i to 1 in the process. The value 0 is copied into the formal parameter i of the method addTwo() during method invocation. However, the formal parameter is local to the method, and changing its value does not affect the value in the actual parameter. The value of variable i in the main() method remains 1.

3.26

(d)

The variables a and b are local variables that contain primitive values. When these variables are passed as parameters to another method, the method receives copies of the primitive values in the variables. The original variables are unaffected by operations performed on the copies of the primitive values within the called method. The variable bArr contains a reference value that denotes an array object containing primitive values. When the variable is passed as a parameter to another method, the method receives a copy of the reference value. Using this reference value, the method can manipulate the object that the reference value denotes. This allows the elements in the array object referenced by bArr to be accessed and modified in the method inc2().

3.27

(d)

The length of the array passed to the main() method corresponds exactly to the number of command-line arguments given to the program. Unlike some other programming languages, the element at index 0 does not contain the name of the program. The first argument given is retrieved using args[0], and the last argument given is retrieved using args[args.length-1].

3.28

(a) and (f)

Values can only be assigned once to final variables. A final formal parameter is assigned the value of the actual parameter at method invocation. Within the method body, it is illegal to reassign or modify the value of a final parameter. This causes a++ and c = d to fail. Whether the actual parameter is final does not constrain the client that invoked the method, since the actual parameter values are copied to the formal parameters.