Monday, 26 October 2009

SCJP Sun Certified Programmer By Kathy Sierra and Bert Bates - Part3

Couple of weeks back i started practicing SCJP Sun Certified Programmer for Java 5 Study Guide By Kathy Sierra and Bert Bates.

Great book written by Kathy Sierra and Bert Bates.

I wanted to share few important quotations found from the third chapter.

1) Octal integers use only the digits 0 to 7. In Java, you represent an integer in octal form by placing a zero in front of the number.

2) Static variables have the longest scope; they are created when the class is loaded, and they survive as long as the class stays loaded in the JVM.

Instance variables are the next most long-lived; they are created when a new instance is created, and they live until the instance is removed.

Local variables are next; they live as long as their method remains on the stack.However, local variables can be alive, and still be "out of scope".

Block variables live only as long as the code block is executing.

3) Array elements are always, always, always given default values, regardless of where the array itself is declared or instantiated.

4) One exception to the way object references are assigned is String. In Java, String objects are given special treatment.String objects are immutable;

Example:


class StringTest {
public static void main(String [] args) {
String x = "Java"; // Assign a value to x
String y = x; // Now y and x refer to the same
// String object

System.out.println("y string = " + y);
x = x + " Bean"; // Now modify the object using
// the x reference

System.out.println("y string = " + y);
}
}


Output:

%java StringTest
y string = Java
y string = Java

5) Shadowing involves redeclaring a variable that's already been declared somewhere else.

The effect of shadowing is to hide the previously declared variable in such a way that it may look as though you're using the hidden variable, but you're actually using the shadowing variable.

You can shadow an instance variable by declaring a local variable of the same name, either directly or as part of an argument:


class Foo {
static int size * 7;
static void changeIt(int size) {
size = size + 200;
Systsm.out.println("size in changelt is " + size);
}
public static void main (String [] args) {
Foo f = new Foo() ;
System.out.println("size = " + size);
changeIt(size);
System.out.println("size after changeIt is " + size);
}
}



The preceding code appears to change the size instance variable in the changeIt() method, but because changeIt() has a parameter named size, the local size variable is modified while the instance variable size is untouched.

Running class Foo prints

%java Foo
size = 7
size in changeIt is 207
size after changelt is 7

Things become more interesting when the shadowed variable is an object reference, rather than a primitive:


class Bar {
int barNum = 28;
}

class Foo {
Bar myBar =new Bar();
void changelt(Bar myBar) {
myBar.barNum = 99;
System.out.println("myBar.barNum in changeIt is " + myBar.barNum);
myBar = new Bar() ;
myBar.barNum = 420;
System.out.println("myBar.barNum in changelt is now " + myBar.barNum);
}
public. static void main (String [] args) {
Foo f = new Foo() ;
System. out .println.("f.myBar.barNum is " + f.myBar.barNum);
f.changeIt {f.myBar);
System.out.println("f .myBar.barNum after changeIt is "
+ f.myBar.barNum) ;
}
}



The preceding code prints out this:

f.myBar.barNum is 28
myBar.barNum in changelt is 99
myBar.barNum in changeIt is now 420
f, myBar. barNum after changeIt is 99

You can see that the shadowing variable (the local parameter myBar in changeIt().) can still affect the myBar instance variable, because the myBar parameter receives a reference to the same Bar object. But when the local myBar is reassigned a new Bar object, which we then modify by changing its barNum value, Foo's original myBar instance variable is untouched.

6) Multidimensional arrays, remember, are simply arrays of arrays. So a two-dimensional array of type int is really an object of type int array (int[]), with each element in that array holding a reference to another int array. The second dimension holds the actual int primitives. The following code declares and constructs a two-dimensional array of type int:


int[] [] myArray = new int [3] [];


7) When you assign an array to a previously declared array reference, the array you're assigning must be the same dimension as the reference you're assigning it to. For example, a two-dimensional array of int arrays cannot be assigned to a regular int array reference, as follows:


int[] blots;
int[][] squeegees = new int [3][] ;
blots = squeegees; // NOT OK, squeegees is a two-d array of int arrays



8) A static initialization block runs once, when the class is first loaded. An instance initialization block runs once every time a new instance is created.

9) Init blocks execute in the order they appear.

Static init blocks run once, when the class is first loaded.

Instance init blocks run every time a class instance is created.

Instance init blocks run after the constructor's call to super().

10) Remember, wrapper reference variables can be null.

Example:


class Boxing2 {
static Integer x;
public static void main(String [] args) {
doStuff(x);
}
static void doStuff(int z) {
int z2 = 5;
System.out.println(z2 + z);
} }



This code compiles fine, but the JVM throws a NullpointerException when it attempts to invoke doStuff(x), because x doesn't refer to an Integer object, so there's no value to unbox.

11) Given a choice compiler will always choose widening over boxing and Widening beats var-args.

Ex:


class AddVarargs {
static void go(int x, int y) { System.out.println("int,int");}
static void go(byte... x) { System.out.println("byte ... "); }
public static void main(String[] args) {
byte b = 5;
go(b,b); // which go() will be invoked?
}
}



Output: int,int


class AddBoxing {
static void go(Integer x) { System.out.println("Integer"); }
static void go(long x) { System.out.println("long"); }

public static void main(String [] args) {
int i = 5;
go(i); // which go() will be invoked?
}
}



Output: long

12) Given a choice compiler always chooses boxing beat var-args.

Ex:


class BoxOrVararg {
static void go(Byte x, Byte y)
{ System.out.println("Byte, Byte"); }
static void go(byte... x) { System.out.println("byte... "); }

public static void main(String [] args) {
byte b = 5;
go(b,b); // which go() will be invoked?
}
}



Output is

Byte, Byte

13) Remember, none of the wrapper classes will widen from one to another! Bytes won't widen to Shorts, Shorts won't widen to Longs, etc.

14) Below are the rules we need to remember regarding widening ,boxing and var-args

Primitive widening uses the "smallest" method argument possible.

Used individually, boxing and var-args are compatible with overloading.

You CANNOT widen from one wrapper type to another. (IS-A fails.)

You CANNOT widen and then box. (An int can't become a Long.)

You can box and then widen. (An int can become an Object, via Integer.)

You can combine var-args with either widening or boxing.

15) The garbage collector is under the control of the JVM. The JVM decides when to run the garbage collector. From within your Java program you can ask the JVM to run the garbage collector, but there are no guarantees, under any circumstances, that the JVM will comply.

16) Java provides you a mechanism to run some code just before your object is deleted by the garbage collector. This code is located in a method named finalize() that all classes inherit from class Object. But any code that you put into your class's overridden finalize() method is not guaranteed to run.

17) It is never legal to include the size of an array in the declaration.

18) Wrapper constructors can take a String or a primitive, except for Character, which can only take a char.

No comments: