Operators and Assignments
In this section you should be able to:
Operators
and Assignments
Category
|
Operators |
Description
|
|
Unary |
++ -- +
- ! ~
( ) |
++ -- + - ~ ! ( ) |
Increment/decrement operators Unary plus/minus (pos/neg) Bitwise inversion Boolean complement Cast |
Arithmetic |
* / % |
* / % |
Multiply Division Modulo operator |
+ - |
+ - |
Plus Minus |
|
Shift |
<<
>> >>> |
<< >> >>> |
Signed left shift Signed right shift Unsigned right shift operator (also known - zero
fill right shift) |
Comparison |
<
<= > >=
instanceof |
< <= > >= instanceof |
Less than Less than or equal to More than More than or equal to Tests the class of an object at runtime |
== != |
== != |
Equal to Not equal to |
|
Bitwise |
&
^ | |
& ^ | |
AND XOR OR |
Short-circuit |
&&
|| |
&& || |
AND OR Used only for Boolean types and can be used to test
the 2nd only if the first doesn’t equate i.e. false && true = false: if
one operand is false the result is false without regard to the other operand.
Similarly true && false = true: if one operand is
true the result is true without regard to the other operand |
Conditional |
?: |
?: |
Also known as ternary operator, works like an
if/else statement A = X ? B : C If X = true A
= B Else A
= C |
Assignment |
= “op=” |
= op= |
Equals Op represents operator, i.e. +=, *= e.g. x = x+ 2; could be written x+=2; |
Conversion
rules in Assignments
In the description below, I have given basic
rules for assignment when source and destination are of different types.
1. If source and destination are of the same type,
assignment happens without any issues.
2. If source is of a smaller size than destination but
source and destination are of compatible types, then no casting is required.
Implicit widening takes place in this case. An example is assigning an int to
a long.
3. If source and destination are of compatible types but
source is of larger size than destination, explicit casting is required. In
this case if no casting is provided then the program does not compile.
Remember these rules when using data types
with the various operators. There will be
questions which may try to catch you out. The following example seems to go
against rule 1 even though the rule is correct, and it gets me every time:
Q: Will
the following code compile?
1.
byte b =
2;
2.
byte b1
= 3;
3.
b = b *
b1;
A. Yes
B. No
A: B.
No
Although the source and destination are the
same, the two operands, which are originally bytes, get converted by
the operator into ints before the multiplication. The result of the
multiplication is an int, which cannot be assigned to byte b.
See the screen shot below showing the code in use in a class called test:
To get the code to perform how I want I need
to change it to something like the following:
1. byte b = 2;
2. byte b1 = 3;
3. b = (byte)(b * b1);
Otherwise I would need to introduce another
variable of the int type to hold the result.
1. byte b = 2;
2. byte b1 = 3;
3. int i = b * b1;
Floating
point numbers
Decimal numbers (for example 1.3) are of the
type double by default. To make them of type float they must be followed by F
or f (example 1.3F or 1.3f).
The
equality operator
The equality operator (==)
when applied to objects, returns true if the two objects have the same
reference value, otherwise false. The
example below illustrates this:
String str1 = “first string”;
String str2 = new String(“first
string”);
String str3 = “first string”;
boolean test1 = (str1==str2);
boolean test2 = (str1==str3);
In the example above test1
is set to false because str1 and str2 point to different references. As str1
and str3 point to the same reference, test2
gets set to true. When a string is initialised without using the new
operator, and with an existing string, then the new string also points to the
first string’s location. So in the example above str1
and str3 point to the same pool of memory and hence test2
gets set to true. The string str2 on the other hand is created using the new
operator and hence points to a different block of memory. Hence test1
gets set to false.
An example of the code above in use is shown
below in a short test program. (if you were to compile the code below you would only
output the results of test1 and test2).
The
conditional operators && and ||
Operator && returns true
if both operands are true, otherwise false. Operator || returns
false if one or the other operands is false, otherwise true. Just as in basic
AND, OR logic.
&& (AND) |
Result |
|
|| (OR) |
Result |
||
false |
false |
false |
false |
false |
false |
|
false |
true |
false |
false |
true |
true |
|
true |
false |
false |
true |
false |
true |
|
true |
true |
true |
true |
true |
true |
The important thing to note about these
operators however, is that they are short-circuited. This means that the left
operand before the right operand. If the result of the operation can be
evaluated after completing the left operand, then the right side is not
computed. In this respect they these operators are different from their
bit-wise counterparts – bit-wise AND (&), and bit-wise OR (|).
The bitwise operators are not
short-circuited. This means that both the operands of the bit-wise operator
will always be evaluated independently of the result of the evaluations.
Storing
integral types
All the integer types in Java™ are
internally stored in two’s complement. In two’s complement,
positive numbers have their corresponding binary representation. Two’s
complement representation of negative numbers is generated using the following
3 step process.
1. First get the binary representation of the number.
2. Then interchange the zeros and ones in the binary
representation.
3. Finally, add one to the result. So for example
two’s complement of -18 (minus 18) would be (assuming one byte
representation)
·
Converting 18 to
binary: 00010010
·
Interchanging
zeros and ones: 11101101
·
Adding 1: 11101110
So 11101110 would be the binary
representation of -18 using two bytes and using two’s complement
representation.
The
shift operators
The shift left operator in Java™ is
“<<”. There are two operators for doing the right
shift. Signed right shift “>>” and unsigned (or zero fill) right shift
“>>>”.
The left shift operator fills the right bits
by zero. The effect of each left shift is multiplying the number by two. The
example below demonstrates this:
int i = 13; // i is 00000000
00000000 00000000 00001101
i = i << 2; // i is now 00000000
00000000 00000000 00110100
After this left shift, i
becomes 52 which is the same as multiplying i by 4.
Zero fill right shift is represented by the
symbol >>>. This operator fills the leftmost bits by zeros. So
the result of applying the operator >>> is always positive. (In two’s complement
representation the leftmost bit is the sign bit. If the sign bit is zero the
number is positive, similarly, if the sign bit is a one then the number is a
negative.) The example below illustrates applying the >>> operator on a number.
int b = 13; // b is 00000000
00000000 00000000 00001101
b = b >>>
2; // b is now 00000000 00000000 00000000 00000011
So the result of doing an unsigned (zero
fill) right shift by 2 on 13 is 3.
The next example explains the effect of
applying the operator >>> on a negative number.
int b = -11; // b is 11111111
11111111 11111111 11110101
b = b >>>
2; // b is now 00111111 11111111 11111111 11111101
So the result of applying an unsigned (zero
fill) right shift operator with operand 2 on -11 (minus 11) is 1073741821.
Signed right shift operator (>>)
fills the left most bit by the sign bit. The result of applying the signed
shift bit has the same sign as the left operand. For positive numbers the
signed right shift operator and the unsigned (zero fill) right shift operator
both give the same results. For negative numbers the results are different. The
example below illustrates the signed right shift.
Int b = -11; // b is 11111111 11111111 11111111 11110101
B = b >> 2; // b is now 11111111 11111111 11111111
11111101
/* 2’s
complement of -3. Here the sign bit 1 gets filled in the two most significant
bits.
The result of doing a signed right shift by
2 on -11 is -3.
Recap
Operator Precedence
Precedence |
Type |
Operator |
Operation |
Associates |
0 |
|
(
) |
parenthesis |
L to R |
1 |
|
[],
., ,, ++, -- |
array
subscript, member selection, comma delimiter, post increment, post decrement |
L to R |
2 |
unary |
++,
--, +, -, ! |
prefix
increment, prefix decrement, positive, negative, NOT |
R to L |
3 |
unary |
(type),
new |
typecast,
object instantiation |
R to L |
4 |
binary
multiplicative |
*,
/, % |
multiplication,
division, modulo |
L to R |
5 |
binary
arithmetic |
+,
-, + |
addition,
subtraction, string concatenation |
L to R |
6 |
binary
shift |
<<,
>>, >>> |
left
shift, signed right shift, unsigned right shift (with 0) |
|
7 |
binary
relational (evaluates to boolean) |
>=,
<=, >, <, instanceof |
greaterThanOrEqual,
lessThanOrEqual, greaterThan, lessThan, type comparison |
L to R |
8 |
binary
equality (evaluates to boolean) |
==,
!= |
EqualTo,
notEqualTo |
L to R |
9 |
binary/boolean
conjunction |
& |
bitwise
AND, boolean AND |
L to R |
10 |
binary/boolean
XOR |
^ |
bitwise
XOR, boolean XOR |
L to R |
11 |
binary/boolean
disjunction |
| |
bitwise
OR, boolean OR |
L to R |
12 |
logical
conjunction |
&& |
logical
AND (short circuits) |
L to R |
13 |
logical
disjunction |
|| |
logical
OR (short circuits) |
L to R |
14 |
tertiary
conditional (evaluates to boolean) |
?: |
(boolean
statement)?(expression if true):(expression if false) |
R to L |
15 |
binary
assignment |
=,
+=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, ^=, |= |
assignment,
plusAssgn, minusAssgn, timesAssgn, dividesAssgn, moduloAssgn, leftShiftAssgn,
rightShiftAssgn, rightShiftAssgnW0, ANDAssgn, XORAssgn, ORAssgn |
R to L |