Previous
Index

Next


Chapter 5) Operators and Assignments

Objective 1, Applying operators

Determine the result of applying any operator including assignment operators and instanceof to operands of any type class scope or accessibility or any combination of these.

The instanceof operator

The instanceof operator is a strange beast, in my eyes it looks like it ought to be a method rather than an operator. You could probably write an great deal of Java code without using it, but you need to know about it for the purposes of the exam. It returns a boolean value as a test of the type of class at runtime. Effectively it is used to say


Is thisclass an instanceof thisotherclasss

If you use it in the following trivial way it does not seem particularly useful

public class InOf {
        public static void main(String argv[]){
        InOf i = new InOf();
               if(i instanceof InOf){
                   System.out.println("It's an instance of InOf");
                }//End if
        }//End of main
}

As you might guess this code will output

"It's an instance of InOf"

However circumstances may arise where you have access to an object reference that refers to something further down the hierarchy. Thus you may have a method that takes a Component as a parameter which may actually refer to a Button, Label or whatever. In this circumstance the instanceof operator can be used to test the type of the object, perform a matching cast and thus call the appropriate methods. The following example illustrates this

import java.awt.*;

public class InOfComp {
        public static void main(String argv[]){
        }//End of main

        public void mymethod(Component c){
        if( c instanceof Button){
                Button bc = (Button) c;
                bc.setLabel("Hello");
                }
                else
        if (c instanceof Label){
                Label lc = (Label) c;
                lc.setText("Hello");
                }
        }//End of mymethod
}

If the runtime test and cast were not performed the appropriate methods, setLabel and setText would not be available. Note that instanceof tests against a class name and not against an object reference for a class.

The + operator

As you might expect the + operator will add two numbers together. Thus the following will output 10 

int p=5; 
int q=5;
System.out.println(p+q);

The + operator is a rare example of operator overloading in Java. C++ programmers are used to being able to overload operators to mean whatever they define. This facility is not available to the programmer in Java, but it is so useful for Strings, that the plus sign is overridden to offer concatenation. Thus the following code will compile

String s = "One"; 
String s2 = "Two" 
String s3 = "";
s3 = s+s2; 
System.out.println(s3);

This will output the string OneTwo. Note there is no space between the two joined strings. 

If you are from a Visual Basic background the following syntax may not be familiar

s2+=s3

This can also be expressed in Java in a way more familiar to a Visual Basic programmer as 

s2= s2+s3

Under certain circumstances Java will make an implicit call to the toString method. This method as it's name implies tries to convert to a String representation. For an integer this means toString called on the number 10 will return the string "10". 

This becomes apparent in the following code 

int p = 10; 
String s = "Two"; 
String s2 = "";
s2 = s + p; 

System.out.printlns(s2);

This will result in the output

Two10

Remember that it is only the + operator that is overloaded for Strings. You will cause an error if you try to use the divide or minus (/ -) operator on Strings.

Assigning primitive variables of different types

A boolean cannot be assigned to a variable of any other type than another boolean. For the C/C++ programmers, remember that this means a boolean cannot be assigned to -1 or 0, as a Java boolean is not substitutable for zero or non zero. 

With that major exception of the boolean type the general principle to learn for this objective is that widening conversions are allowed, as they do not compromise accuracy. Narrowing conversions are not allowed as they would result in the loss of precision. By widening I mean that a variable such as a byte that occupies one byte (eight bits) may be assigned to a variable that occupies more bits such as an integer.

However if you try to assign an integer to a byte you will get a compile time error 

byte b= 10; 
int i = 0; 
b = i;

    

Primitives may be assigned to "wider" data types, a boolean can only be assigned to another boolean

As you might expect you cannot assign primitives to objects or vice versa. This includes the wrapper classes for primitives. Thus the following would be illegal

int j=0; 

Integer k = new Integer(99); 

j=k; //Illegal assignment of an object to a primitive

An important difference between assigning objects and primitives is that primitives are checked at compile time whereas objects are checked at runtime. This will be covered later as it can have important implications when an object is not fully resolved at compile time.

You can, of course, perform a cast to force a variable to fit into a narrower data type. This is often not advisable as you will loose precision, but if you really want enough rope, Java uses the C/C++ convention of enclosing the data type with parenthesis i.e. (), thus the following code will compile and run

public class Mc{ 
public static void main(String argv[]){ 
    byte b=0;  
    int i = 5000;  
    b = (byte) i;  
    System.out.println(b); 
    }  
}

The output is 

-120

Possibly not what would be required.

Assigning object references of different types

When assigning one object reference to another the general rule is that you can assign up the inheritance tree but not down. You can think of this as follows. If you assign an instance of Child to Base, Java knows what methods will be in the Child class. However a child may have additional methods to its base class. You can force the issue by using a cast operation.

Object references can be assigned up the hierarchy from child to base.



The following example illustrates how you can cast an object reference up the hierarchy

class Base{}

public class ObRef extends Base{
public static void main(String argv[]){
        ObRef o = new ObRef();
        Base b = new Base();
        b=o;//This will compile OK
        /*o=b;  This would cause an error indicating
                an explicit cast is needed to cast Base 
                to ObRef */
   
        }
}
       

The ++ and – Operators

You would be hard pressed to find a non trivial Java program that does not use the ++ or – operators, and it can be easy to assume that you know all you need to know for the purposes of the exam. However these operators can be used in pre-increment or post increment. If you do not understand the difference you can loose exam points on an apparently easy question. To illustrate this, what do you think will be sent to the console when the following code is compiled and run?

public class PostInc{
    static int i=1;
    public static void main(String argv[]){
    System.out.println(i++);
    }
}

If you compile and run this code the output is 1 and not 2. This is because the ++ is placed after the number 1, and thus the incrementation (the adding of 1) will occur after the line is run. The same principle is true for the – operator.



The bit shifting operators

I hate bit the whole business of bit shifting. It requires filling your brain with a non intuitive capability that an very small number of programmers will ever use. Typical examples of where bit shifting is used "in the real world" is cryptography and low level manipulation of image files. You can do an awful lot of Java programming without ever having to shift a single bit yourself. But that's all the more reason to learn it especially for the exam as you probably won't learn it via any other means. The exam generally presents at least on question on the bit shifting operators. If you are from a C++ background you can be mislead into thinking that all of your knowledge can transfer directly to the Java language.

To understand it you have to be fairly fluent in at thinking in binary, ie knowing the value of the bit at each position i.e.

32, 16, 8, 4, 2, 1

Not only do you need to appreciate binary, you need to have a general grasp of the concept of “twos compliment” numbering system. With this system of representing numbers the leading bit indicates if a number is positive or negative or positive. So far so intuitive, but it starts to get strange when you understand that numbering system works like a car odometer. Imagine every little wheel had a 1 or a zero on it. If you were to turn it back from showing

00000000 00000000 00000000 00000001

one more click it would show

11111111 11111111 11111111 11111111 11111111

This would represent -1. If you click it back one more place it would show

11111111 11111111 11111111 11111111 1111110



Those examples are slightly oversimplified. Until I studied for the Java Programmers exam I had assumed that twos compliment representation only referred to the use of the leading bit to indicate the sign part of the number. As you can see it is somewhat more complex than that. To help you understand the notation a little more I have written an apparently trivial program that will show the bit pattern for a number given on the command line. It could be much improved by breaking the bits into chunks of eight, but it is still handy for getting the general picture.

public class Shift{
    public static void main(String argv[]){
    int i = Integer.parseInt(argv[0]);
    System.out.println(Integer.toBinaryString(i));
    }
}



If you are from a C/C++ background you can take slight comfort from the fact that the meaning of the right shift operator in Java is less ambiguous than in C/C++. In C/C++ the right shift could be signed or unsigned depending on the compiler implementation. If you are from a Visual Basic background, welcome to programming at a lower level.

Note that the objective only asks you to understand the results of applying these operators to int values. This is handy as applying the operators to a byte or short, particularly if negative, can have some very unexpected results.

Unsigned right shift >>> of a positive number

I will start with the unsigned right shift because it is probably the weirdest of the bit shifts and requires an understanding of twos complement number representation to fully understand. It gets extra weird when negative numbers are involved so I will start with positive numbers. The unsigned right shift operation treats a number as purely a bit pattern and ignores the special nature of the sign bit. Remember that once you start looking at a number as a sequence of bits any bit level manipulation can have some unexpected results when viewed as a normal number.

The unsigned right shift operation takes two operands, the first number is the number that will have its bits shifted and the number after the operand is the number of places to be shifted. Thus the following

3 >>> 1

Means that you will shift the bits in the number 3 one place to the right.

The twos complement numbering system means that the leading bit in a number indicates if it is positive or negative. If this value is zero the number is positive, if it is 1 it is negative. With the unsigned right shift the leading bit position is always filled with a zero. This means an unsigned right shift operation always results in a positive number.

If you think of the number 3 as being represented by

011

And you shift it one place to the right with

3 >> 1

you will end up with

001

Note that the bits that have new values moved into them "fall off the end" of the number and are effectively thrown away.

If you perform the shift two places to the right it will come as little surprise that the number becomes zero as the number zero is moved into all of the bit positions. If you keep increasing the number of places you are shifting by such as 6 places, 10 places 20 places you will find the result stays at zero as you might expect. If you persist however when you get to

3 >>>32



The surprising result is 3. Why is this so?

Behind the scenes before the shift a mod 32 is performed on the operand. The modulus operator (indicated in java by the % character divides one number by another and returns the remainder. Whilst the mod operator is being performed on a number smaller than itself the original number is returned so whilst the number of places being shifted is less than 32 the mod operation is not noticed. Once you get to 32 places it starts to kick in.

Thus 32 % 32 returns zero as there is nothing left over and the number returned by the operation

3 >>> 32 

is 3, ie 3 is shifted 0 places.

I did not find this at all intuitive at first so I wrote the following code

 public class shift{
  static int i=2;
   public static void main(String argv[]){ 
        System.out.println(32 % 32);
        System.out.println( 3  >>> 32); 
        } 
 }

The output of this code is

0
3
    


A mod 32 is performed on the shift operand which affects shifts of more than 32 places



Unsigned shift >>> of a negative number

An unsigned shift of a negative number will generally result in a positive number. I say generally as an exception is if you shift by exactly 32 places you end up with the original number including the sign bit. As explained earlier, the reason you generally get a positive number is that any unsigned right shift replaces the leading sign bit with a zero which indicates a positive number.

The results of an unsigned shift of a negative number can seem very odd at times, take the following

System.out.println( -3 >>> 1);

You might think that this would result in a number such as

1

ie the sign bit is replaced by a zero resulting in a positive number and the bits are shifted one place to the right. This is not what happens, the actual result is

2147483646

Strange but true.

The reason behind this odd result is to do with the way twos complement number representation works. If you imagine the bits in a number represented by the wheels on the display of a car odometer, what happens when you count down from the largest possible number to zero, and then go to the first number below zero?. All of the digits are set to 1 including the sign bit to indicate a negative number. When you perform an unsigned right shift you are breaking this way of interpreting the numbers and treating the sign bit as just another number. So although you started off with a small negative number such as -3 in the example you end up with a large positive number. You may get a question on this in the exam that asks you to identify the result of an unsigned shift of a negative number. The one correct answer may seem very unlikely.



A unsigned right shift >>> by a positive amount of a small negative number will result in a large positive number returned.



The signed shift operators << and >>

The << and >> operators set “new” bits to zero. Thus in the example

System.out.println(2 << 1)



This shift moves all bits in the number 1 two places to the left placing a zero in each place from the right. Thus

Thus the value

010

becomes

100

Or decimal four. You can think of this operation as a repeated multiplication by two of the original number. Thus the result of

System.out.println(2 << 4)

is 32

Which you can think of as

2 * 2 = 4 (for the first place of the shift)

2 * 4 = 8 (for the second place of the shift)

2 * 8 =16 (for the third place of the shift)

2 * 16 =32 (for the fourth place of the shift)

This way of thinking all goes horribly wrong when you get to the point of bits “falling off the end”. Thus the output of

System.out.println(2<<30)

is

-2147483648

This may seem horribly counter-intuitive, but if you think that the single bit representing the 2 has been moved to the left most position it now represents the largest negative number that can be stored as an integer. If you shift by one more place ie

system.out.println(2 << 31)

The result is zero as every bit position is now zero and the bit from the number 2 has fallen off the end to be discarded.

With the signed right shift, the left hand (new) bits take the value of the most significant bit before the shift (by contrast with the zero that is put in the new places with the left shift). This means that the right hand shift will not affect the sign of the resulting number.

2 >> 2;

This shift moves all bits in the number 2 two places to the right Thus

Thus the value

0010

becomes

0000

Or decimal zero (well zero in any other base as well I suppose).

This is the equivalent of performing a repeated integer division, in this case resulting in zeros in every position.



The signed right shift operation >> results in a number with the same sign bit

I have created an applet that allows you to try out the various shift operations and see both the decimal and bit pattern results. I have included the source code so you can see how it works, check it out at

BitShift Applet

Operator Precedence

Operator precedence is the order of priority in which operators get performed. The following table is a summary of the operator precedence.

Operator Precedence

()

++expr --expr +expr -expr ~ !

* / %

+ -

<< >> >>>

< > <= >= instanceof

== !=

&

^

|

&&

||

? :

= += -= *= /= %= &= ^= |= <<= >>= >>>=



I tems on the same row have the same precedence. Generally in real world programming you will indicate the order that operators are expected to be performed by surrounding expressions with braces. This means you can get by without actually learning the order of precedence and it should make it obvious for other programmers who read your code. However it is possible that you may get questions in the exam that depend on understanding operator precedence, particularly on the common operators +, -, *.

If the idea of operator precedence doesn't mean much to you, try to work out what the output of the following code will be.

public class OperPres{
    public static void main(String argv[]){
    System.out.println(2 + 2 * 2);
         System.out.println(2 + (2 * 2));
    System.out.println(8 / 4 + 4);
    System.out.println(8 /(4 +4));
    int i = 1;
    System.out.println(i++ * 2);

    }



Does the first statement 2 + 2 * 2 mean add 2 + 2 and then times the result by 2 resulting in an output of 8, or does it mean multiply 2 * 2 and then add 2 to give a result of 6. Similar questions can be asked of the other calculations. The output of this program by the way is 66612.

    
   

Questions

Question 1)

Given the following classes which of the following will compile without error?

interface IFace{}

class CFace implements IFace{}

class Base{}


public class ObRef extends Base{
public static void main(String argv[]){
        ObRef ob = new ObRef();
        Base b = new Base();
        Object o1 = new Object();
        IFace o2 = new CFace();
        }
}

1) o1=o2;
2) b=ob;
3) ob=b;
4) o1=b;


Question 2)

Given the following variables which of the following lines will compile without error?

String s = "Hello";
long l = 99;
double d = 1.11;
int i = 1;
int j = 0;

1) j= i <<s;
2) j= i<<j;
3) j=i<<d;
4)j=i<<l;

Question 3)

Given the following variables

char c = 'c';
int i = 10;
double d = 10;
long l = 1;
String s = "Hello";



Which of the following will compile without error?

1) c=c+i;
2) s+=i;
3) i+=s;
4) c+=s;


Question 4)

What will be output by the following statement?

System.out.println(-1 >>>1);

1) 0
2) -1
3) 1
4) 2147483647


Question 5)

What will be output by the following statement?

System.out.println(1 <<32);

1) 1
2) -1
3) 32
4)-2147483648


Question 6)

Which of the following are valid statements?

1) System.out.println(1+1);
2) int i= 2+'2';
3) String s= "on"+'one';
4) byte b=255;


Question 7)

What will happen when you attempt to compile and run the following code?

Public class Pres{
    public static void main(String argv[]){
    System.out.println( 2 * 2 | 2);

   }
}

1) Compile time errors, operators cannot be chained together in this manner
2) Compilation and output of 4
3) Compilation and output of 6
4) Compilation and output of 2



Question 8 )

What will happen when you attempt to compile and run the following code?

public class ModShift{
    static int i = 1;
    static int j =1;
    static int k = 0;
    public static void main(String argv[]){
    i = i << 32;
    j = j >>32;
    k = i + j;
    System.out.println(k++);
    }

1 )Compile time error
2) Compilation and output of 3
3) Compilation and output of -3
4) Compilation and output of 2

Question 9)

What will happen when you compile and run the following code?

public class Shift{
    static int i;
    static int j;
    public static void main(String argv[]){
    i = 2;
    j = i <<31;
    i =i++;
    System.out.println(j);
    System.out.println(i);

    }
}

1) -2147483648 followed by 2
2) -2147483648 followed by 3
3) 0 followed by 3
4) 0 followed by 2

Question 10)

What will be output by the following program.

public class Mac{
    public static void main(String argv[]){
    System.out.println( -1 >>>1  & 2); 
   }
}

1) 2147483647
2) -1
3) 10
4) 2

Answers

Answer 1)

1)o1=o2;
2)b=ob;
4)o1=b; 
       

Answer 2)

2)j= i<<j;
4)j=i<<l;
       

Answer 3)

2)s+=i;

If you want to test these possibilities, try compiling this code

public class Llandaff{ 
        public static void main(String argv[]){ 
        Llandaff h = new Llandaff(); 
        h.go(); 
        } 

        public void go(){ 
                char c = 'c'; 
                int i = 10; 
                double d = 10; 
                long l = 1; 
                String s = "Hello"; 
                //Start commenting these out till it all compiles
                c=c+i; 
                s+=i; 
                i+=s; 
                c+=s; 
        } 
} 
       

Answer 4)

4) 2147483647

Although you might not be able to come up with that number in your head, understanding the idea of the unsigned right shift will indicate that all the other options are not correct.

Answer 5)

1) 1

With the left shift operator the bits will "wrap around". Thus the result of

System.out.println(1 <<31);

would be -2147483648

Answer 6)

1) System.out.println(1+1);
2) int i= 2+'2';
Option 3 is not valid because single quotes are used to indicate a character constant and not a string.
Option 4 will not compile because 255 is out of the range of a byte

Answer 7)

Compilation and output of 4

The * operator has a higher precedence than the | operator. Thus the calculation is equivalent to (2 * 2) | 2 or you can consider it 4 * 2. The | operator compares the bits in each position and if a bit is present in a position in either number then the output number also has a bit in that position. The bit sequence for 4 is 100 and the bit sequence for 2 is 10. The result of the | operation is thus 110 which is 6 decimal

Answer 8 )

4) Compilation and output of 2

When you shift a number by 32 places a mod 32 is performed on the number of places to shift. 32 % 32 means how much is left over if you divide 32 by 32 and the answer to that question is 0. So the number is shifted by zero places, ie the original number is returned. This question has the somewhat sneaky twist that the output uses the post increment operator ++. This means the number is incremented after the current line has finished executing, so the numbers 1 and 1 are added and 2 is sent to the output.

Answer to Question 9 )

4) 0 followed by 2

This should not be as hard as it looks. A knowledge of the number of bits in an int and the bit pattern of the number 2 combined with an understanding of the signed left shift operation will indicate that the single bit of the number 2 falls off the left hand side of the number, resulting in a zero in every bit position

The fact that the output includes 2 not 3 is because the post increment operation adds 1 to i after the assignment with the = operator.

Answer to Question 10 )

4) 2

This question might make you want to throw your hands up in the air and click at random, but if you have the right background knowledge you can work out the answer. If you understand twos compliment representation you will know that -1 is represented by a 1 in every position of the int. According to operator precedence you should know that the >>> operation happens before the & . If you modify the code to remove the & operation you will find the output to be the big number given as option 1. However the operation to & the result by 2 means that the bits will only be set in the output where there is a set bit in both the numbers. The resulting output is 2.


Other sources on this topic

The Sun Tutorial
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/operators.html
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/expressions.html

The Java Language Specification: Operator Precedence
http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#23213

Jyothi Krishnan on this topic at

http://www.geocities.com/SiliconValley/Network/3693/obj_sec5.html#obj15

Article on Binary/Hex/Decimal Numbers by Jane Griscti
http://www.janeg.ca/scjp/oper/binhex.html

Bitshifting from JavaRanch
http://www.javaranch.com/campfire/StoryBits.jsp

Connecticut State University
http://chortle.ccsu.ctstateu.edu/cs151/Notes/chap09B/ch09B_1.html




Previous
Index

Next