Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 49

What are the potential trips/traps in SCJP exam? Two public classes in the same file.

Two public classes in the same file. Main method calling a non-static method. Methods with the same name as the constructor(s). Thread initiation with classes that dont have a run() method. Local inner classes trying to access non-final vars. Case statements with values out of permissible range. Math class being an option for immutable classes !! instanceOf is not same as instanceof Private constructors An assignment statement which looks like a comparison if ( a=true)... System.exit() in try-catch-finally blocks. Uninitialized variable references with no path of proper initialization. Order of try-catch-finally blocks matters. main() can be declared final. -0.0 == 0.0 is true. A class without abstract methods can still be declared abstract. Map doesnt implement Collection. Dictionary is a class, not an interface. Collection is an Interface where as Collections is a helper class. Class declarations can come in any order ( derived first, base next etc. ). Forward references to variables gives compiler error. Multi dimensional arrays can be sparce ie., if you imagine the array as a matrix, every row need not have the same number of columns. Arrays, whether local or class-level, are always initialized, Strings are initialized to null, not empty string. An empty string is NOT the same as a null string. A declaration cannot be labelled. continue must be in a loop ( for, do , while ). It cannot appear in case constructs. Primitive array types can never be assigned to each other, eventhough the primitives themselves can be assigned. ie., ArrayofLongPrimitives = ArrayofIntegerPrimitives gives compiler error eventhough longvar = intvar is perfectly valid. A constructor can throw any exception. Initilializer blocks are executed in the order of declaration. Instance initializer(s) gets executed ONLY IF the objects are constructed. All comparisons involving NaN and a non-Nan would always result false. Default type of a numeric literal with a decimal point is double. integer (and long ) operations / and % can throw ArithmeticException while float / and % will never, even in case of division by zero. == gives compiler error if the operands are cast-incompatible. You can never cast objects of sibling classes( sharing the same parent ), even with an explicit cast. .equals returns false if the object types are different. It does not raise a compiler error. No inner class can have a static member.

Aman's Points To Remember for SCJP Last Updated: 08/15/00 7:10 pm

The datatype in a switch statement must be convertible to int, i.e., only byte, short, char and int can be used in a switch statement, and the range of the datatype used must cover all of the cases (case statements). An integer literal (w/o a decimal pt) is assumed to be a 32-bit int primitive, but a value containing a decimal point is assumed to be a 64-bit double. Wrapper classes for primitives produce immutable objects. Java characters are 16-bit unicode characters, and they can be initialized in the following ways: o o o o o char c1 = '\u0057' char c1 = 'w' char c1 = 87 char c1 = (char) 87 char c1 = '\r' (acc to RHE)

instanceof operator can take a class, an interface or an array type as an argument. To test if an object is an array, use: myObject.getClass().isArray();

MenuContainer interface is implemented by Container, Frame, Menu and MenuBar An identifier must begin with a letter, a dollar sign ($), or an underscore. Subsequent characters maybe letters, $, underscore, or digits, but NOT other characters liek %, &, etc. The keywords syncrhonized, private and protected cannot be used with a class. A variable declared inside a try block cannot be used in the catch block. If no super-class constructor is explicitly called, and there is no call to other constructor (using this(..)), the default constructor of the superclass (w/o any arguments) is automatically called. wait(), notify() and notifyAll() are the instance methods of Object class, not Thread class (but they are inherited by Thread class). stop(), suspend() and resume() are deprecated methods in Java 1.2 References to member methods are resolved at runtime using the type of object, but the references to member variables are computed at compile time using the type of the reference. Javadoc documentation does not list private variables and methods. A valid overload differs in teh number or types of arguments. Difference is return type only is not a valid overload. Inner classes defined local to a block may not be declared to be static. Mmember inner classes cannot have the same name as enclosing class, but they CAN subclass the enclosing class.

If an instance of the inner class had to refer to the associated instance of the enclosing class, then the following syntax could be used: o EnclosingClass myPart = EnclosingClass.this;

No datatype is automatically converted to a char. However, you can cast to a char. Solaris uses pre-emptive scheduling; Windows & Mac uses time-slicing. A monitor is any object that has some synchronized code. If you have a sycnhronized method in a class, a subclass with an overriding method does not have to declare it to be synchronized. A static method may not be overridden to be non-static, and vice-versa. equals() method just returns false even if the object reference types are different. It does not throw an exception. The add(..) method of the Set returns false if you atttempt to add an element with a duplicate value, but no exception is thrown. Constructors CAN be private. Anonymous classes cannot have constructors. -(i) = ~(i) + 1 The test condition (assuming i is an int): If (i=2) will give a compiler error because the test condition expects a boolean and the assignment (i=2) returns an int

While using the RandomAccessFile constructor, if the file is not present, a mode "r" throws a FileNotFoundException. If "rw" mode is used, a new file is created with zero length. Applets can't have a constructor with arguments. It can have constructor with no arguments. Any component can have menu barsor pull-down menus, although only frames have a method for adding a menubar. Double.NaN == Double.NaN //returns false But, if Y = X = Double.NaN, X.equals (Y) returns true

Also, +0.0 == -0.0 //returns true But, if Y = +0.0 and X = -0.0 , X.equals (Y) returns false

For shift operators, >>, << and >>>, unary numeric promotion is applied to each operand separately, and the datatype of the resulting expression is the same as the left operand. instanceof is not same as instanceOf. The instanceof operator tests whether its first operand is an instance of its second.

op1 instanceof op2 op1 must be the name of an object and op2 must be the name of a class. An object is considered to be an instance of a class if that object directly or indirectly descends from that class. There is nothing like instanceOf in java x instanceof P If x is null, the instanceof test simply returns FALSE --it doesn't cause an exception String[] str = new String[10]; now str instanceof String[] ===returns true str instanceof Object ===returns true str instanceof Object[] ===returns true str instanceof String ===Compilation Error If a = null, System.out.println (a); prints null, and does not throw an exception. A class SHOULD (MUST) be declared abstract if it has one or more abstract methods. An abstract class can also have non-abstract methods. You can also declare a class to be abstract even when it has no abstract methods, so that users can't instantiate it and are forced to subclass it. In an interface, ALL methods must be abstract. Infact, all methods in an interface are implicitly abstract. Also, all methods and variables in an interface are implicitly public, and must declare them to be public while implementing the interface. It is a compile-time error for a constructor to invoke itself by calling this(), but there is a bug which allows cyclic constructor invocation, that is constructor 1 calls constructor 2 and vice-versa. If you call Thread.sleep() in a synchronized code, the thread does not give up the lock, it keeps the lock during sleeping. It gives up the lock only when calling the method wait(). abs (Integer.MIN_VALUE) = Integer.MIN_VALUE No duplicate objects are allowed in a Set, and duplicate means that the equals() method returns true. So, there can't be two separate objects having same value in a set. If run() is a static method, and me() is also a static method returning null, then me().run() WILL compile and run correctly. In other words, ((StaticTest)(null)).run(); //will work fine (where StaticTest is a class) Byte b1 = new Byte("172") b1.toString() == b1.toString() is false. The toString() method for the Wrapper classes (except Boolean) creates a string over the heap, and returns a reference to that string. A new string is created eacht time, hence the result false. Each instance of a thread belongs in a ThreadGroup (even if you don't explicitly set it). In the latter case, the threadgroup is the same that of the thread which created it. If i=0 i++ will result in i=1 i=i++ will not change the value of i. It'll remain at 0. You can use super.var to access a variable in the superclass.

Even new Boolean (null); will create a Boolean with a false value, and won't throw an exception. This is true although null is a null literal, and not the same as "null" string. Interfaces can have access modifiers of public or blank, just like classes. UTF-8 is ASCII An array of primitives of on type canot be cast into an array of primitives of another type. The \uxxxx notation can be used anywhere in the source to represent Unicode characters, e.g., char a = '\u0061' ch\u0061r a = 'a char \u0061 = 'a' are all valid (and equivalent) statements.

An empty file is a valid source file. A source file can contain an optional package declaration, any number of import statements and any number of classes and interface definitions. The modulus operator (%) can be used with integral as well as floating datatypes. Extended assignment operators, e.g., *=, += ensure than an implicit narrowing conversion takes place which makes the result fit into the target variable, e.g., b = b + i; // is illegal. b+=i //is legal

In an assignment of the following type , where i=0: a[i] = i = 9; a[0] will be assigned the value of i=9, i.e., 9, as opposed to a[9], which you might think. That is, the initial value is used to determine which element is to be assigned the value.

Elements in an unitialized array object get the default value corresponding to the type of elements. This is true, regardless of whether the variable is an instance variable or a local variable. Local variables cannot be declared to be static and cannot be given an accessibility modifier. The declaration of a non-abstract method must provide an implementation ( { }, at least !! ). A constructor does not declare any return type, not even a void. A constructor cannot be final, abstract or static. Normal methods (non-constructor) MUST specify a return type, at least a void !! You cannot pass void as a parameter to a method, e.g., void method (void) is wrong. Anonymous arrays, (analogous to anonymous classes) have a form: new int[] {3,2,4,6,1}

and are usually used for being passed to a method as a parameter. The main() method CAN throw checked exceptions. It is not possible to use a break statement inside an if block. Break statements can only be used for o o o o o Do-while While For Labelled blocks Switch statements

catch and finally blocks can themselves throw checked exceptions which are handled in the usual way. An overriding method must have the same method name, same parameters, and same return type as the original method. Whether parameters in the overriding method should be declared final is at the discretion of the subclass. Only methods that are accessible may be overridden. So, private methods can't be overridden. this() and super() cannot both occur in the same constructor. If a constructor does not have either a this() or a super() as its first statement, then a super() call to the default constructor of the superclass is automatically inserted. An interface can define constants. Such constants are considered to be public, static and final regardless of whether these modifiers are specified or not. In the case of multiple inheritance, any name conflicts are resolved using fully qualified names. A non-static inner class cannot have any static members. Package member classes, local classes and anonymous classes cannot be declared to be static. The static initializer block cannot be contained in a method. In a method declaration, the modifiers, e.g., public, static, must precede the return type. All method defined in Set are also defined in Collection, but the same is not true for List. Java returns the same string object reference for almost all of the methods invoked on a string object, provided the result of the operation happened to be the same as that of the string object on which the method is invoked. According to the preceding point, a comparison like this: "abc".substring(0)=="abc" would return true.

For the wrapper classes, a new string reference is created each time, except for Boolean class, which returns a reference to "true" or "false" from the string pool.

String comparisons for strings created at runtime, return false, e.g., if ja="ja" and va = "va" and java="java" java == "java" //is true java = "ja" + "va" //is true java = "ja" + va //is false

A vector can only store object references, NOT primitives. length is a field (instance variable) for an array, but a string length() is a method. Math.round (-4.7) = -5 Math.ceil (-4.7) = -4.0 Math.floor (-4.7) = -5.0 Native methods cannot be abstract, but they can be static. Garbage collection cannot be turned off. double c = Math.floor (Double.MIN_VALUE) // = 0.0 double c = Math.ceil (Double.MIN_VALUE) // = 1.0 For Math.round() o o Add 0.5 to the number to be rounded. Do a Math.floor() on that number.

getValue() method of the Adjustment class returns an int value for the adjustment setting. When a thread executes a waitForID() call on a MediaTracker, the current thread stops executing. The finally block is always executed except when there is a System.exit call. Local inner classes cannot be declared public, private, protected, or static. Member inner classes can be private, protected, public, final or abstract. Component class is an abstract class. Vector v = new Vector (initial capacity, capacity increment), e.g., Vector v = new Vector (5, 10), where 5 is the initial capacity of the vector and 10 is the capacity increment.

There is no concat() method for StringBuffer class. replace() is a String method. The read() method returns -1 when it reaches end of the file. Using the modifier static or final with transient is legal.

An abstract method cannot be private, static, final, native or synchronized. Object method equals() will throw a NullPointerException if the calling object is null. If the argument is null, it returns false. If a method is there in a subclass, but not in the base class, then you can't use a reference variable of the base type to access that method, even if the object is of the subclass type. You'll be required to cast the reference to subclass type. getWhen() method of InputEvent class is used to extract the instant at which the InputEvent (e.g., MouseEvent) was generated. Boolean and Character classes do no extend java.lang.Number. Character class does not have a valueOf() mehod. add() and addItem() both can be used to add an item to a choice. Math.ceil (-0.5) = -0.0 ( not 0.0 !!) The order of the floating/double values is: -infinity -> -ve nos/fractions -> -0.0 -> 0.0 -> +0.0 -> +ve nos/fractions -> +infinity

2 + 3 + "" = 5 2 + "" + 3 = 23 " + 2 + 3 = 23 A label CAN be placed in front of another label. You can't assign a 2nd value to a final variable. You CAN assign the value like this: final int MAX_INT; MAX_INT = 30; but you cannot reassign the value.

null, true and false, are NOT keywords. They are literals. null is a NULL literal. True and false are boolean literals. But remember that they ARE reserved words. You can put a semicolon after '}' If i = 3, then print3 (i, ++i, ++i +++i) is equivalent to print3 (3, 4, 5+6) print3 (i, ++i, i+++ i ++) is equivalent to print3 (3, 4, 4+5)

Once an array is created, its length can never be changed. The array-size specifier must be an integral type, you can't use long, etc.

StringBuffer class does not ovverride equals method. So, the equals method returns false when passed two different StringBuffer objects, containing the same values. float f = 40.0 // illegal because 40.0 is double byte b = 40 // legal although 40 is int int arr[] = new int [-10] compiles correctly, but throws a NegativeArraySizeException at runtime.

Static variables CAN exist inside an inner class if the inner class is also static. square() or sqr() methods do not exist for Math class, because same functionality can be provided by pow(). An inner class can actually be a subclass of the outer class. Runtime exceptions can be avoided with a correctly coded program. However, checked exceptions can arise even in a correctly coded program. The implementation of toString() method for the String class simply returns a reference to the current object, i.e., String s1 = new String("Java"); String s2 = s1.toString(); s1 == s2 // is true

abs, min, max and round are the only methods (out of the methods which you need to remember for SCJP ;-) ) of the Math class with return an int (also). There is a static method for Integer class: public static String toString(int I) which can be used to return a String object representing the specified integer. There are similar methods for Long, Float, Double, Byte, Short.

Overriding methods cannot throw checked exceptions not thrown by overridden methods, but they CAN throw unchecked exceptions not thrown by overridden methods, like ArrayIndexOutofBoundsException. Unary numeric promotion is not applied to ++ and You can also run a class from the command line, even if it is not declared public. protected means accessible by all the subclass, as well as all the classes in the same package. When -ve signs are involved in % operator, compute the result by ignoring the sign(s) and then, just apply the sign of the left operand to the result, e.g., -7 % -2 = - (7%2) = - 1

10

instanceof operator simply returns false if the left hand argument is a null value. It does not throw an exception. The default no-argument constructor created by Java is public. When asked to write a statement, be sure to end it with a semicolon. The order of the exceptions specified by a method should be more specific exception followed by less specific exception. A try block must be followed by one of these combinations: o o o One or more catch blocks. A finally block. Both catch and finally blocks.

The main method can be declred without the public modifier, and it'll run fine. A more specific catch block cannot follow a general one. The program won't compile. If you have two methods in a class: o o public int method (int b, float x) public int method (float b, int x) and you call one of these methods as method (2, 5), the program won't compile, because the reference to the method is ambigous. However, if you call the method as method (2, 5.0), it'll compile and run fine.

reverse() is a method of StringBuffer class, not String class. In case of shift-operators, only primitive integral types (byte, short, char, int, and long) can be used, and unary numeric promotion is applied separately to each operand.

If you find any problems with these notes, please do mail me at: amanwarch@rocketmail.com

11

Top-level and Inner Classes Top-Level Class

by Koray Guclu

Top-level classes can only have public, abstract, and final modifiers, and it is also possible to
not define any class modifiers at all. This is called default/package accessibility.

Besides that, private, protected, and static modifiers cannot be used when declaring top-level
classes.

It is an error to declare the same modifier twice; the compiler will throw a Repeated modifier
exception.

More than one top-level class can be defined in a Java source file, but there can be at most one
public top-level class declaration. The file name must match the name of the public class.

The file name can be anything, provided there is not a public class definition. If there is more than
one class declaration in a source file, each will be compiled into separate .class files.

An abstract class is a class which may have incomplete implementations for its methods, some of
the methods can have implementation and some others can be empty method declarations.

If an abstract class is going to be subclassed, all of its incomplete method implementations must
be implemented in the subclass, or the subclass must be declared as abstract too; otherwise the compiler will complain.

A class that is declared with a final modifier cannot be subclassed. If you want your class not to
be able to subclassed, use the final modifier.

A class, defined with an abstract modifier cannot be instantiated, because they have incomplete
implementations. This type of class needs to be subclassed and have implementation for its incomplete methods before instantiation.

Multiple inheritance is not allowed in Java. A class can be declared to implement multiple
interfaces but can only extend at most one class.

An interface is the same as an abstract class, but you cannot define any method implementations
at all. Abstract classes allow having some method implementations. Method implementations cannot be defined when an interface is concerned.

Interfaces are defined with the interface keyword. An interface doesn't need abstract and class keywords. Member variables are implicitly defined as
public static final. An abstract class can have a constructor(s), but the constructor(s) must be implemented. An Interface must not have a constructor at all. Nested top-level classes and interfaces (Static nested classes/interfaces) Nested top-level classes are declared within an enclosing class.

12

Nested top-level classes are always defined with a static keyword. A nested top-level class/interface is defined as a static member of its enclosing class/interface. For
this reason, it can be accessed or instantiated without any instance of an enclosing class. Since it is declared static, it can only access static members of enclosing class. Do not confuse nested toplevel classes with top-level classes -- they are not the same. Nested top-level classes can not have the same name as the enclosing class; doing so will cause an exception. ( same holds true for inner classes also. Gives compilation error )

Since nested top-level classes are declared static, they act like any other static features of a class.
The following example illustrates the instantiation of a nested top-level class. Outer.Inner theInner= new Outer.Inner();

There is no such thing as an inner interface. Because, interfaces are always implicitly static. They
are always top-level, not inner. Inner classes cannot have any static modifiers at all. 1. 2. 3. 4. 5. 6. 7. 8. 9. interface IOuter { class ICinner {interface IInner {};}; //OK static class ICSinner {interface IInner {};}; //OK interface IInner {interface Inner{ };};//OK class Outer { //class Cinner {interface IInner {}; } //Error. Inner class can't have static members static class CSinner {interface IInner {}; }; //OK }

10. } Inner Classes

Declaration of a class within another class is called an inner class. It is basically a name for nested
classes.

A top-level class can be accessed directly without an instance of an enclosing class, but an inner
class requires an instance of an outer class. We have used the static modifier when defining a toplevel class. If a static modifier is used, there is no requirement for an enclosing class, like a toplevel class. For that reason, you can think every type of inner class as a non-static class. The compiler will throw an error if you want to declare static initializers, because inner classes do not allow static initializer code blocks.

Inner classes can have any access modifier, like public, protected, and private, or no access
modifier, but it cannot have any static members.

13

An inner class can extend or implement any class or interface, there are no restrictions or obligations. There are three types of inner classes. Member Classes (Non-static inner classes) Local Classes Anonymous Classes

"An inner class is a nested class that is not explicitly or implicitly declared static." ('8.1.2) [1]. Member Classes (Non-static Inner Classes)

A member class is declared as a member of an enclosing class. A member class is declared like a
top-level inner class except for a static modifier. Member classes do not have static modifiers. Member classes require an instance of an enclosing class and every instance of a member class holds an implicit reference to its enclosing class. The following example illustrates the instantiation of a member class. Outer.Inner theInner = new Outer().new Inner(); //or Outer theOuter = new Outer(); Outer.Inner theInner = theOuter.new Inner();

Member classes cannot have any static member unless it is a compile-time constant.
( i.e. static final variables ) "Inner classes may not declare static members, unless they are compile-time constant fields .". A member class can access all the fields and methods (even private) of an enclosing class.

A member class can be declared as public, protected, private, abstract, final, or static.
Note that when you declare a member class with a static modifier it will not be an inner class anymore. It will be a top-level nested class. Local Classes A local class is declared inside a method, a constructor, a static initializer, or an instance initializer.

A local class cannot have a static modifier. A local class is analogous to a local variable in some
ways.

You cannot use public, protected, private, or static modifiers in a local class analogous to a local
variable.

A local class can access all the fields and methods of the enclosing class but can only access final
modifiers declared inside a method. A local class cannot be accessed from outside the method.

14

Local classes cannot be declared as static, but they can be defined in a static context (for example, in a static method). Anonymous Classes An anonymous class is one declared without a name. This is a convenient solution for most situations. You can create an object on the fly this way. For example, event listeners can be created by the use of anonymous inner classes.

Anonymous classes do not allow the use of extends and implements clauses and access
modifiers. An anonymous class doesn't have constructors, and it is not allowed to define a constructor. Since anonymous classes don't have names, there is no way to define a constructor. Anonymous classes can either implement an interface or extend a class but cannot do both. The general form is: //interface implementation new InterfaceName() {} //extends a class new ClassName() {} The interface name is the name of the interface that is going to be implemented, and the class name is the name of the class that is going to be extended. They are not the name of our newly created class. It is the name of the class that we intend to implement or extend. Reference Card Top level nested class Declaration Context Accessibility Modifiers As static class member All Non static inner class As non-static class member All Yes Local class Anonymous class

In block with non- In block with non-static static context context None Yes None Yes

Outer instance No

Direct Access to Static members All members in All members in All members in enclosing enclosing in enclosing enclosing enclosing context + context + local final context context context local final variables variables Defines static or Both static and Only non-static Only non-static non-static non-static members Constructors Yes Yes Yes Only non-static

No

15

Can use extends Yes or implements clauses?

Yes

Yes

No

16

Programming With Assertions

Sun.com:

An assertion is a statement in the JavaTM programming language that enables you to test your
assumptions about your program. Each assertion contains a boolean expression that you believe will be true when the assertion executes. If it is not true, the system will throw an error. By verifying that the boolean expression is indeed true, the assertion confirms your assumptions about the behavior of your program, increasing your confidence that the program is free of errors. assertions serve to document the inner workings of your program, enhancing maintainability. assert Expression1 ; o where Expression1 is a boolean expression. o When the system runs the assertion, it evaluates Expression1 and if it is false throws an AssertionError with no detail message. assert Expression1 : Expression2 ; o Expression1 is a boolean expression. o Expression2 is an expression that has a value. o Expression2 cannot be an invocation of a method that is declared void. o Use this version of the assert statement to provide a detail message for the AssertionError. o The system passes the value of Expression2 to the appropriate AssertionError constructor, which uses the string representation of the value as the error's detail message. o The purpose of the detail message is to capture and communicate the details of the assertion failure. The message should allow you to diagnose and ultimately fix the error that led the assertion to fail. o Note that the detail message is not a user-level error message, so it is generally unnecessary to make these messages understandable in isolation, or to internationalize them. o The detail message is meant to be interpreted in the context of a full stack trace, in conjunction with the source code containing the failed assertion. o Like all uncaught exceptions, assertion failures are generally labeled in the stack trace with the file and line number from which they were thrown. o The second form of the assertion statement should be used in preference to the first only when the program has some additional information that might help diagnose the failure.

In some cases Expression1 may be expensive to evaluate. To ensure that assertions are not a performance liability in deployed applications, assertions can be
enabled or disabled when the program is started, and are disabled by default. Disabling assertions eliminates their performance penalty entirely.

Once disabled, they are essentially equivalent to empty statements in semantics and performance.
Putting Assertions Into Your Code situations where it is good to use assertions.

o Internal Invariants o Control-Flow Invariants o Preconditions, Postconditions, and Class Invariants There are also a few situations where you should not use them:

17

o Do not use assertions for argument checking in public methods.


Argument checking is typically part of the published specifications (or contract) of a method, and these specifications must be obeyed whether assertions are enabled or disabled. Another problem with using assertions for argument checking is that erroneous arguments should result in an appropriate runtime exception (such as IllegalArgumentException, IndexOutOfBoundsException, or NullPointerException). An assertion failure will not throw an appropriate exception.

o Do not use assertions to do any work that your application requires for correct
operation. Because assertions may be disabled, programs must not assume that the boolean expression contained in an assertion will be evaluated. // Broken! - action is contained in assertion assert names.remove(null); // Fixed - action precedes assertion boolean nullsRemoved = names.remove(null); assert nullsRemoved; // Runs whether or not asserts are enabled o As a rule, the expressions contained in assertions should be free of side effects: o evaluating the expression should not affect any state that is visible after the evaluation is complete. o One exception to this rule is that assertions can modify state that is used only from within other assertions. Internal Invariants

Use an assertion whenever you would have written a comment that asserts an invariant. For
example, you should rewrite the previous if-statement like this: if (i % 3 == 0) { ... } else if (i % 3 == 1) { ... } else { assert i % 3 == 2 : i; ... } Note, incidentally, that the assertion in the above example may fail if i is negative, as the % operator is not a true modulus operator, but computes the remainder, which may be negative.

Another good candidate for an assertion is a switch statement with no default case. o The absence of a default case typically indicates that a programmer believes that one of
the cases will always be executed.

18

The assumption that a particular variable will have one of a small number of values is an invariant that should be checked with an assertion. default: assert false : suit;

If the suit variable takes on another value and assertions are enabled, the assert will fail and an AssertionError will be thrown. o An acceptable alternative is: default: o throw new AssertionError(suit);

This alternative offers protection even if assertions are disabled, but the extra protection adds no cost: the throw statement won't execute unless the program has failed. Moreover, the alternative is legal under some circumstances where the assert statement is not. If the enclosing method returns a value, each case in the switch statement contains a return statement, and no return statement follows the switch statement, then it would cause a syntax error to add a default case with an assertion. (The method would return without a value if no case matched and assertions were disabled.)

Control-Flow Invariants

place an assertion at any location you assume will not be reached.


The assertions statement to use is: void foo() { for (...) { if (...) return; } assert false; // Execution should never reach this point! } Note: Use this technique with discretion. If a statement is unreachable as defined in the Java Language Specification , you will get a compile time error if you try to assert that it is not reached. Again, an acceptable alternative is simply to throw an AssertionError. Preconditions, Postconditions, and Class Invariants assert false;

While the assert construct is not a full-blown design-by-contract facility, it can help support an
informal design-by-contract style of programming. This section shows you how to use asserts for: Preconditions what must be true when a method is invoked. o Preconditions Lock-Status Preconditions preconditions concerning whether or not a given lock is held.

Postconditions what must be true after a method completes successfully. Class invariants what must be true about each instance of a class.

19

By convention, preconditions on public methods are enforced by explicit checks that throw
particular, specified exceptions.

Do not use assertions to check the parameters of a public method.


o o An assert is inappropriate because the method guarantees that it will always enforce the argument checks. It must check its arguments whether or not assertions are enabled. throw only an AssertionError.

o Further, the assert construct does not throw an exception of the specified type. It can You can, however, use an assertion to test a nonpublic method's precondition that you believe
will be true no matter what a client does with the class. Lock-Status Preconditions

Classes designed for multithreaded use often have non-public methods with preconditions
relating to whether or not some lock is held.

Note that it is also possible to write a lock-status assertion asserting that a given lock isn't held.
For example, it is not uncommon to see something like this: // Recursive helper method - always called with a lock on this. private int find(Object key, Object[] arr, int start, int len) { assert Thread.holdsLock(this); // lock-status assertion ... } Postconditions

You can test postcondition with assertions in both public and nonpublic methods.
public BigInteger modInverse(BigInteger m) { if (m.signum <= 0) throw new ArithmeticException("Modulus not positive: " + m); ... // Do the computation assert this.multiply(result).mod(m).equals(ONE) : this; return result; } Occasionally it is necessary to save some data prior to performing a computation in order to check a postcondition. You can do this with two assert statements and a simple inner class that saves the state of one or more variables so they can be checked (or rechecked) after the computation. Class Invariants

20

A class invariants is a type of internal invariant that applies to every instance of a class at all times, except when an instance is in transition from one consistent state to another. A class invariant can specify the relationships among multiple attributes, and should be true before and after any method completes. For example, suppose you implement a balanced tree data structure of some sort. A class invariant might be that the tree is balanced and properly ordered. The assertion mechanism does not enforce any particular style for checking invariants. It is sometimes convenient, though, to combine the expressions that check required constraints into a single internal method that can be called by assertions. Continuing the balanced tree example, it might be appropriate to implement a private method that checked that the tree was indeed balanced as per the dictates of the data structure: // Returns true if this tree is properly balanced private boolean balanced() { ... } Because this method checks a constraint that should be true before and after any method completes, each public method and constructor should contain the following line immediately prior to its return: assert balanced(); It is generally unnecessary to place similar checks at the head of each public method unless the data structure is implemented by native methods. In this case, it is possible that a memory corruption bug could corrupt a "native peer" data structure in between method invocations. A failure of the assertion at the head of such a method would indicate that such memory corruption had occurred. Similarly, it may be advisable to include class invariant checks at the heads of methods in classes whose state is modifiable by other classes. (Better yet, design classes so that their state is not directly visible to other classes!) Removing all Trace of Assertions from Class Files strip assertions out of class files entirely. o o o this makes it impossible to enable assertions in the field, it also reduces class file size, possibly leading to improved class loading performance. In the absence of a high quality JIT, it could lead to decreased footprint and improved runtime performance.

The assertion facility offers no direct support for stripping assertions out of class files.

The assert statement may, however, be used in conjunction with the "conditional compilation"
idiom enabling the compiler to eliminate all traces of these asserts from the class files that it generates: static final boolean asserts = ... ; // false to eliminate asserts if (asserts) assert <expr> ; Requiring that Assertions are Enabled Programmers of certain critical systems might wish to ensure that assertions are not disabled in the field.

21

The following static initialization idiom prevents a class from being initialized if its assertions have been disabled: static { boolean assertsEnabled = false; assert assertsEnabled = true; // Intentional side effect!!! if (!assertsEnabled) throw new RuntimeException("Asserts must be enabled!!!"); } Put this static-initializer at the top of your class. Compiling Files That Use Assertions javac -source 1.4 MyClass.java This flag is necessary so as not to cause source compatibility problems.

Enabling and Disabling Assertions By default, assertions are disabled at runtime. Two command-line switches allow you to selectively enable or disable assertions.

To enable assertions at various granularities, use the -enableassertions, or -ea, switch. To disable assertions at various granularities, use the -disableassertions, or -da, switch.
You specify the granularity with the arguments that you provide to the switch: o no arguments Enables or disables assertions in all classes except system classes. Enables or disables assertions in the named package and any subpackages.

o packageName... o ...
Enables or disables assertions in the unnamed package in the current working directory.

o className
Enables or disables assertions in the named class

For example, the following command runs a program, BatTutor, with assertions enabled in only
package com.wombat.fruitbat and its subpackages: java -ea:com.wombat.fruitbat... BatTutor If a single command line contains multiple instances of these switches, they are processed in order before loading any classes.

The above switches apply to all class loaders. With one exception, they also apply to system
classes (which do not have an explicit class loader). The exception concerns the switches with no arguments, which (as indicated above) do not apply to system classes. This behavior makes it easy to enable asserts in all classes except for system classes, which is commonly desirable.

To enable assertions in all system classes, use a different switch: -enablesystemassertions, or -esa.

22

To disable assertions in system classes, use -disablesystemassertions, or -dsa. For example, the following command runs the BatTutor program with assertions enabled in
system classes, as well as in the com.wombat.fruitbat package and its subpackages: java -esa -ea:com.wombat.fruitbat...

The assertion status of a class (enabled or disabled) is set at the time it is initialized, and does
not change. There is, however, one corner case that demands special treatment. It is possible, though generally not desirable, to execute methods or constructors prior to initialization. This can happen when a class hierarchy contains a circularity in its static initialization.

If an assert statement executes before its class is initialized, the execution must behave as if
assertions were enabled in the class. Compatibility With Existing Programs

The addition of the assert keyword to the Java programming language does not cause any
problems with preexisting binaries (.class files).

If you try to compile an application that uses assert as an identifier, however, you will receive a
warning or error message.

In order to ease the transition from a world where assert is a legal identifier to one where it isn't,
the compiler supports two modes of operation in this release:

o source mode 1.3 (default) the compiler accepts programs that use assert as an
identifier, but issues warnings. In this mode, programs are not permitted to use the assert statement.

o source mode 1.4 the compiler generates an error message if the program uses assert as
an identifier. In this mode, programs are permitted to use the assert statement.

Unless you specifically request source mode 1.4 with the -source 1.4 flag, the compiler operates in
source mode 1.3. If you forget to use this this flag, programs that use the new assert statement will not compile.

AssertionError a subclass of Error rather than RuntimeException

Switch -ea -da -ea:<classname> -da:<classname> -ea:<packagename>... Java -ea Java -da

Example

Meaning Enable assertions by default Disable assertions by default Enable assertions in class AssertPackageTest Disable assertions in class AssertPackageTest Enable assertions in package pkg0

Java -ea:AssertPackageTest Java -da:AssertPackageTest - Java ea:pkg0...

23

-da:<packagename>... -esa -dsa

Java da:pkg0... Java esa Java -dsa

Disable assertions in package pkg0 Enable assertions in system classes Disable assertions in system classes

24

Assertion dos Do use to enforce internal assumptions about aspects of data structures Do use to enforce constraints on arguments to private methods Do use to check conditions at the end of any kind of method Do use to check for conditional cases that should never happen Do use to check for conditional cases that should never happen, even if youre really sure they can never happen Do use to check related conditions at the start of any method Do use to check things in the middle of a long lived loop

Assertion donts Dont use to enforce command-line usage Dont use to enforce constraints on arguments to public methods Dont use to enforce public usage patterns or protocols Dont use to enforce a property of a piece of user supplied information Dont use as a shorthand for if (something) error(); Dont use as an externally controllable conditional Dont use as a check on the correctness of your compiler, operating system, or hardware, unless you have a specific reason to believe there is something wrong with it and are in the process of debugging it

Do use in lieu of nothing

25

JQPlus Tips and Study Notes for Sun Certified Java2 Programmer's Exam Section 1 Declarations and Access Control Write code that declares, constructs, and initializes arrays of any base type using any of the permitted forms both for declaration and for initialization.

Creating an Array requires 3 things: Declaration: int[] iA; Integer tA[]; Student[] sA; Size is never specified in declaration. Allocation: iA = new int[10]; You are allocating 10 places for storing 10 integers. sA = new Student[5]; You are allocating 5 places for storing 5 references to Student Objects. Note: Not 5 places to store Student objects! Size must always be specified in allocation. Initialization: Remember, when you allocate an array space is allocated only to store the references. In case of primitive types the space contains 0 (for integral types), 0.0 (for floating points) or false( for booleans). In other cases, these places are initialized to point to 'null'. 2 ways to explicitly initialize arrays: First way: for (int i = 0; i < iA.length; i++) iA[i] = 5; for (int i = 0; i < sA.length; i++) sA[i] = new Student(); Second way: (Initialization the time of allocation.) iA = new int[] {5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; sA = new Student[] { new Student(), new Student(), new Student(), new Student(), new Student() }; The above statements are creating an int array of 10 elements and a Student array of 5 elements respectively. Note that, the size is not specified explicitly. Multidimensional Arrays: Java supports Arrays of Arrays. This means you can have something like: int[][] iAA; iAA is an array. And each of it's elements points to an object which is an array of ints. It can be instantiated like this: int[][] iAA = new int[2][3]; ie. An array containing 2 elements. Each element in turn points to another array of ints containing 3 elements. Rules for multidimensional array are exactly same as single dimensional array. Eg. in the above case, the 2 places of iAA are pointing to null. Or iAA = new int[][]{ {1, 2, 3}, null }; Here, first element of iAA is pointing to an array containing {1, 2, 3} and the second element is pointing to null. Array features: Array size is always maintained with the array object as a final instance variable named 'length'. Ex. iAA.length . You cannot assign any value to it. ie. you cannot do iAA.length = 4;

26

Array Pitfalls: An Array is a first class java object. Eg. Assuming int[] iA == new int[3]; (iA instance of Object) is true. When you create an array of primitive type eg. int[] iA == new int[3]; , you create 1 object and three primitives initialized to 0. But when you create an array of any java object, eg. String[] sA == new String[3]; , you create 1 object and 3 places initially pointing to 'null' to hold 3 string objects. Difference between int[] a, b; // a and b both are arrays and int a[], b; // a is an array but b is just an int. Indexing starts with 0. ie. First element is accessed as: iA[0] = 10;

Declare classes, inner classes, methods, instance variables, static variables, and automatic (method local) variables making appropriate use of all permitted modifiers (such as public, final,static, abstract, and so forth). State the significance of each of these modifiers both singly and in combination, and state the effect of package relationships on declared items qualified by these modifiers.

There are 5 kind of classes: 1. The standard/normal one. This is called " TopLevel class ". 2. Static Member Class or (previously known as "Top Level Nested Class"): A static class defined inside a class. Just like static methods, it can only access static members of the outer class. 3. Inner class: An inner class is a nested class that is not explicitly or implicitly declared static. Inner classes cannot declare static initializers or member interfaces. Inner classes cannot declare static members, unless they are compile-time constant fields eg. public final static int CODE = 100; //this is valid inside an inner class. 4. Local Class: A local class is a nested class that is not a member of any class and that has a name. All local classes are inner classes. Every local class declaration statement is immediately contained by a block. Local class declaration statements may be intermixed freely with other kinds of statements in the block.The scope of a local class declared in a block is the rest of the immediately enclosing block, including its own class declaration. Local class cannot have any of these modifiers:: public, protected, private, or static. 5 Anonymous Class: It is a class that does not have a name. There are only 2 ways to create such classes: SomeClass sc = new SomeClass() { public void m1() { } }; SomeClass is an existing class. So, sc refers to an object of 'anonymous' class which is a subclass of SomeClass. SomeInterface sc = new SomeInterface() {

27

public void m1() { } //implement all methods of SomeInterface. }; SomeInterface is an existing interface. So, sc refers to an object of 'anonymous' class which implements SomeInterface. An anonymous class is never abstract or static. An anonymous class is always an inner class. An anonymous class is always implicitly final. A nested class is any class whose declaration occurs within the body of another class or interface. A top level class is a class that is not a nested class. A member class is a class whose declaration is directly enclosed in another class or interface declaration. Similarly, a member interface is an interface whose declaration is directly enclosed in another class or interface declaration. Member interfaces are always implicitly static so they are never considered to be inner classes. A Class : CAN BE public, final, abstract CANNOT BE synchronized, native, private, protected, static, volatile Members of a class: . Fields : CAN BE public, private, protected, static, volatile, final CANNOT BE synchronized, native, abstract . Methods : CAN BE public, private, protected, static, native, synchronized, final, abstract CANNOT BE volatile . Fields inside a method are called 'automatic' or 'local' variables. Such fields CANNOT BE public, private, protected, synchronized, native, abstract, static, volatile

Points to remember:

You need to have a very good understanding of access levels (what private, protected, public means and how it works). Read this topic from any good java book. Few points to remember about private, protected, public (also known as access modifiers): Only applied to class(only public can be applied to top level class declaration) and class members (constructors, fields or methods). Fields inside methods cannot have these modifiers and they are visible only inside that method. Members may be inaccesible even if the class is accessible. It depends on members access modifier. But if the class is not accessible, the members will not be accessible, even if they are declared public. If no access modifier is specified, ie. default access, then it means it is only visible in that package ie. all classes in the same package can access it. "private" means only that class can access the member. Also, "private" means, private to a class not to an object ie. An instance of a class can access the private features of another instance of the same class. "protected" means all classes in the same package (like default) and sub-classes in any package can access it.

28

static members cannot access non-static members. But non-static members can access static members. Order of restrictiveness: (Least Restrictive) public < protected < default (no modifier) < private (Most Restrictive)

For a given class, determine if a default constructor will be created, and if so, state the prototype of that constructor.

Default constructor will be created ONLY when a class does not define any constructor explicitly. For eg public class A { public A() //This constructor is automatically inserted by the compiler as there is no other constructor defined by the programmer explicitly. { super(); //Note this. It is calling super(). This means the super class should have a constructor that takes no parameters. Otherwise this class won't compile. } } public class A { //Compiler will not generate any constructor as programmer has defined a constructor. public A(int i) { //do something } } The access modifier of the default constructor (provided by the compiler, not the one that you write) is same as that of the class. In the top case, it is public because the class is public. See a detailed example here. Another related example.

State the legal return types for any method given the declarations of all related methods in this or parent classes.

29

First, very imp. points: A method signature includes: name of the method, no. of parameters, class/type of parameters. A method signature DOES NOT include: return type, any other modifier(abstract, final, static etc), throws clause. Eg. If you say two methods have same signature, that means, their name, no. or params and class/type of params are same. NOTHING CAN BE SAID ABOUT ANYTHING ELSE.

Two cases that you need to consider: 1. Overriding: A subclass has a method with same signature as a method in super class. This means, subclass method is overriding the superclass method. OR super class method is overridden by the subclass method. Rules: Overriding method's return type MUST be the same as that of overridden method's return type. Overriding method's throws clause must be compatible. Ie. it can throw any of the exceptions declared in the throws clause of parentclass's (overridden) method, it can throw any SubClass of execptions defined in parentclass's (overridden) method, it may choose not to throw ANY EXCEPTION. In applying the above rule, only CHECKED (ie. exceptions NOT extending from RuntimeException class) are to be considered. ANY METHOD CAN THROW UnChecked exception without declaring.

2. Overloading : A class having more than 1 methods with same name but different parameter list. (Note that this makes their signature different). There are no rules. In affect, overloaded methods are entirely independent of each other.Remember, if signature is different, it is a different method.

30

Section 2 FLOW CONTROL AND EXCEPTION HANDLING Write code using if and switch statements and identify legal argument types for these statements.

Consider the following if-else block: public void method1(boolean flag) //0 { boolean bool = false; int i = 20; if(flag) { System.out.println("first if"); } else if(flag == bool) { System.out.println("first else-if"); } else if( bool ) { System.out.println("second else if"); } else { System.out.println("last else"); } if( i = 30 ){ ... } //invalid because the expr. i = 30 returns a an int value 30 if( i == 30){ ... } //valid if( bool = true ){ ... } //valid because the expr. bool = true returns a boolean value true int k; //Note that k is uninitialized here. bool = true; if(bool) { k = 100; //Note that k is being initialized here. And this will always get executed as bool is true; } System.out.println(k); //Still this will NOT work. } Rules:

31

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26.

An if condition MUST be a boolean. If you put an expression in the if condition, the value of that expression must be of type boolean. In a chained if : else-if : else construct, the 'else' attaches to the nearest 'if' above it. So, the above construct is equiv. to: if(flag) { System.out.println("first if"); } else { if(flag == bool) { System.out.println("first else-if"); } else { if( bool ) { System.out.println("second else if"); } else { System.out.println("last else"); } } }

------------------------------------------------------------------Consider the following switch block: public void method1(integraltype i) //0 { int k = 30; switch(i) { case 100 : System.out.println(100); //1 case 150 : System.out.println(150); break; //2 invalid if i is of type bytecase 3.2 : System.out.println(i); //3 invalid default : System.out.println(i); //position of default may be anywhere. case 'c' : System.out.println(i); //4 case true : System.out.println(i); //5 invalid case k : System.out.println(i); //6 invalid } }

32

Rules: 1. 2. 3. 4. 'i' could be of type byte, char, short, int. It cannot be of type long, float, double, boolean or any kind of Object. So, //3 and //5 are invalid. The case value should be a compile time constant. So, //6 is not valid. The case value should 'fit' into the type of the case variable. Ex. if 'i' is of type byte then //2 is invalid. 'break' after every case is not necessary. If it is not there after a case, then the control falls through until a break or end of case. So, if i is 100, the above block will print 100 and 150. Write code using all forms of loops including labeled and unlabeled use of break and continue, and state the values taken by loop control variables during and after loop execution.

It is best to read Chapter 14 Blocks and Statements from JLS. It will look a bit intimidating for the first time, but don't give up. It'll pay off. Write code that makes proper use of exceptions and exception handling clauses (try, catch, finally) and declares methods and overriding methods that throw exceptions.

Consider the following method: public void method1() throws IOException //0 { try { throw new FileNotFoundException("FNE"); //System.out.println("This line Will never get executed"); //Compile time error : Unreachable code. } catch(NullPointerException ne) { throw new FileNotFoundException("FNE"); } catch(FileNotFoundException fe) { //This block will NOT catch FileNotFoundException thrown by the catch block above. //This block will ONLY catch FileNotFoundException thrown by the try block. throw new EOFException("EOF"); } finally { //This block has nothing to do with exception catching. That means if you throw an exception in try or catch block, either you have to provide an appropriate catch block or declare it in the throw clause of the method.

33

//It provides a way to the programmer to make sure that code in this block always executes. //Executes even if there is a return in try/catch blocks. //DOES NOT EXECUTE if there is System.exit() in try/catch blocks. } } Concept: There are lot of rules regarding what exceptions can a method throw and they all seem to be very confusing. But they all stem from the same concept, Plug and Play. New code should not break pre-existing code. Consider a component (not an AWT component but any s/w component) C that has a method m. Method m has declared IOException in it's throws clause. Say there is another component U, that uses C (and calls m). It needs to catch IOException, which it does and every thing is fine. Now, instead of C, a subclass of C (say NewC) is supplied to U. As NewC is a subclass of C, U shouldn't feel a difference. It's ok even if the method m of NewC, starts throwing FileNotFoundException because FileNotFoundEx is a subclass of IOException and U is already catching it. It is somethig like this: //in a user component U { ... C c = getC(); //somehow gets the component C. It may actually be NewC. try { c.m(); //can potentially throw IOException. So needs a try/catch block. } catch(IOException ioe) //It'll work even if m() throws FileNotFoundException. { //handle exception } ... } The above code in U will fail if m() throws some other exception like Exception or say, java.rmi.RemoteException. Now, it should be pretty clear to you that the restrictions imposed on the overriding method about exception are to promote component based architecture which allow you to treat s/w as components which you can take out and replace. In short, an overriding method can throw any subclass of exceptions declared in the the throws clause of the superclass's method. It CANNOT throw super class exception or any new exception. Can an overriding method have no throws clause if the overridden method does have one? Imagine such a situation and view it from the perspective shown above and you should get your answer. Hint: Think about whether the above code will fail or not if m() of NewC throws no exception.

34

Section 3 Garbage Collection State the behavior that is guaranteed by the garbage collection system, and write code that explicitly makes objects eligible for collection.

You can answer all the questions if you keep the following rules in mind. Only thing guaranteed by the GC mechanism is : IF an object is really being destroyed, it's finalize() method would already have been called. Note: It doesn't say anything about when will an object be GCed etc. An object is eligible for garbage collection, if the only references to that object are from other objects that are also eligible for garbage collection. Note: It doesn't say anything about circular references. It depends on the actual JVM implementation. You CANNOT precisely say when the GC thread will run. Neither can you make the GC thread to run when you want. Note: You can call System.gc() etc. but this only requests the JVM to run the GC thread. You may set all the reference variables pointing to an object to null. This will enable the GC to collect this object. But that does not mean the object will really be GCed. It is possible that the GC thread may not run at all for the whole life of the program.

Some Points to Remember:

finalize() Method: Signature : protected void finalize() throws Throwable { } It is used to release system resources like File handles, Network connections etc. But not memory. Memory can only be release by the GC thread. All objects have a finalize method as it is implemented in the Object class. But unlike constructors, finalize() does not call super class's finalize(). So, it is advisable (NOT REQUIRED) to put super.finalize() in the code of your finalize() method so as to give a chance to the super class to cleanup it's resources. The order in which finalize methods are called may not reflect the order in which objects are destroyed. It will be called ONLY ONCE for an object by the garbage collector. If any exception is thrown in finalize, the object is still eligible for garbage collection (depends on the GC mechanism). You can resurrect an object by creating an active reference to it in this method. You may call finalize() explicitly, but it would be just like another method call and will not release the memory.

35

finalize can be overloaded, but only the method with above mentioned signature will be called by the GC.

36

Section 4 Language Fundamentals Identify correctly constructed source files, package declarations, import statements, class declarations (of all forms including inner classes), interface declarations and implementations (for java.lang.Runnable or other interface described in the test), method declarations (including the main method that is used to start execution of a class), variable declarations and identifiers.

Structure of source files: An empty file is a valid java src file. Package statement (if exists) should be the first statement. (comments before it are ok!). Next should be the import statements. (if any). Last, should be the class/interface declaration. Method declaration for the standard main: public static void main(String[] args); Main method can also be final, native, synchronized. No matter whether other declarations (like private, protected) work on your m/c, for the purpose of the exam, it should be public.

Variable Declarations and Identifiers: Rules: A valid java identifier is composed of a sequence of java letters (this includes uppercase and lowercase ASCII latin letters and _ , $) and digits, the first of which must be a letter. (Valid: _123, a$2 NOT VALID: 123$, goto) It cannot be same as any java Keywords (eg. while, for, class etc) or literals (ie. true, false or null). Class names can serve as a valid identifier. eg. String String = "asd"; //This is valid. Pitfalls: If you have a main method like: public static int main(String[] args){ return 10; } (Note return type.) It will compile but the program will throw exception at runtime saying there is no main method. Same will be the case if you have: public static void main(String args){} A class without a main method may be run by JVM, if its base class has a valid main method. State the correspondence between index values in the argument array passed to a main method and command line arguments. Identify all Java Programming Language keywords and correctly constructed identifiers.

Consider this: public class TestClass { public static void main(String[] args) {

37

System.out.println("Hello, World!"); } } Points to remember: args will NEVER be null. If no argument is passed, args.length will be 0. If the above program is run with the command line: "java TestClass hello world", then args[0] will be "hello" and args[1] will be "world". UNLIKE IN C/C++, the word 'java' or the name of the class is not passed. Language keywords: Here's a list of Java's keywords. These words are reserved--you cannot use any of these words as names in your Java programs. true, false, and null are not keywords but they are reserved words, so you cannot use them as names in your programs either. State the effect of using a variable or array element of any kind when no explicit assignment has been made to it.

Three Important points: Class members (static/non-static) are ALWAYS initialized automatically to their default values. Variables declared in methods (local variable) are NEVER initialized automatically. You must initialize them before using them. Whenever you "ALLOCATE" an array (ie. new int[3] or new Object[5] etc), the elements are automatically initialized to the default value of their type. Understand what is meant by default values: It is the value assigned by the JVM to a variable. Primitive variables are initialized to 0 (for integral types: byte, char, short, int, long), 0.0 (float and double), false (booleans). Object variables (including arrays) are initialized to null.

Example: class TestClass { int i; //initialized to 0 float f; //initialized to 0.0 boolean bool; //initialized to false int[] iA; //initialized to null: S.o.p(iA) will print 'null' //S.o.p(iA[0]) will throw NullPointerException String[] sA; //initialized to null: S.o.p(sA) will print 'null'

public void m1() //to see about local variables

38

{ int k; //WILL NOT BE INITIALIZED. S.o.p (k); ERROR, k is not initialized! int[] jA; //WILL NOT BE INITIALIZED. S.o.p (jA); ERROR, jA is not initialized! int[] kA = new int[3]; //elements are initialized automatically to { 0, 0, 0} because default value of int is 0 String[] sA = new String[3]; //elements are initialized automatically to { null, null, null} because default value of Object is null. } } State the range of all primitive data types and declare literal values for String and all primitive types using all permitted formats, bases, and representations.

Range of primitives: boolean : true/false byte (8 bits => 2^8 values) : -128 to 127 (-2^7 to 2^7 -1) short (16 bits => 2^16 values) : -32768 to 32767 (-2^15 to 2^15 -1) char (16 bits => 2^16 values) : 0 to 65536 (0 to 2^16 -1) int (32 bits => 2^32 values) : -2^31 to 2^31 -1 long (64 bits => 2^64 values) : -2^63 to 2^63 -1 float 32 bits double 32 bits .3e2 is a valid float but e2 is not. e2 is parsed as a variable name. Octal numbers are written by prepending 0 in front of the no. Eg. 012 is 12 in octal. Hex numbers are written by prepending 0x in front of the no. Eg. 0x12 is 12 in hex. Read following links to understand how the conversions from Binary to octal to decimal to hex are done. Conversions of float and double are way out of scope. Don't worry about them. http://www.belmont.cc.oh.us/dews/stupro/stupro13/stupro13.htm http://www.tpub.com/neets/book13/53j.htm http://www.danbbs.dk/~erikoest/hex.htm OR http://www.danbbs.dk/~erikoest/octal.htm http://www2.gasou.edu/student/gsi23996/RHelp/binary.html

39

Section 5 Operators and assignments Determine the result of applying any operator, including assignment operators, instanceof, and casts to operands of any type, class, scope, or accessibility, or any combination of these.

There are different kinds of operators. 1. Unary operators. 1.1 Increment and Decrement operators : (++ and -- ) You can apply these in two ways: postfix and prefix form. In post-fix form( eg. x++ ) value of the variable/expression is modified after the value is taken for the execution of statement. In prefix form( eg. + +x) , value of the variable/expression is modified before the value is taken for the execution of statement. x = 3; y = 1; y = x++; S.o.p(x+" "+y); //will print 4, 3 x = 3; y = 1; y = ++x; S.o.p(x+" "+y); //will print 4, 4 x = 3; x = x++; // Will print 3 !!! Why? Read on... Steps: .Take the value of x (ie.3 ) and keep in the register. .Increment x (so, x becomes 4). .Assign the value kept in the register to x. So, x again becomes 3. 1.2 Unary minus and unary plus( + -) : + has no effect other than to stress positivity. - negates an expressions value. (2s complement for integral expressions) int i = 3; i = -i; S.o.p(i); //will print -3 i = Integer.MIN_VALUE; i = -i; //Here, i will still be Integer.MIN_VALUE because -ive of Integer.MIN_VALUE exceeds Integer.MAX_VALUE by 1 so it does not fit into an int. 1.3 Boolean Negation (!) : Inverts the value of a boolean expression. boolean flag = false; S.o.p( !flag); //will print 'true' 1.4 Complement ~ (Only for integral types) Inverts the bit pattern of an integral expression. int i = 12; // 0000 0000 0000 0000 0000 0000 0000 1100 i = ~i; // 1111 1111 1111 1111 1111 1111 1111 0011 1.5 Cast () : Forces the compiler to cast one type of value to another type. Compiler still checks whether this cast is possible or not. If a compiler can prove that the given cast can never be valid then it give a compile time error.

40

int 300; // 0000 0000 0000 0000 0000 0001 0010 1100 , doesn't fit into byte. byte b = (byte) i; //the cast fits shoves 300 into a byte but takes only last 8 bits: 0010 1100, other bits are lost. So, b gets 44 instead of 300. Consider this: class A { } class B { } .... A a = new A(); B b = new B(); Object o = a; //All objects are Objects, so no cast is needed. A a1 = (A) o; //All objects are not objects of class A, so cast is needed. Compiler sees that a variable of class Object can point to an object of class A, so ok. B b1 = (B) a; //ERROR, compiler sees that a variable of class A, can NEVER point to an object of class B so there is no point in trying to cast a to b. Arithmetic operators - ( *, / , %, +, - ) (Applied only to numeric types except + which can be applied to Strings) : Important Point: All arithmetic operations are done after promoting (if needed) both the operands to 'int. And the result is always atleast an int. That means, is any of the operands is smaller than an int, then it will be promoted to either an int or to the type of other operand if it is bigger than int. ie. byte b1 = 10; byte b2 = 20; byte b3 = b1 + b2; //Will not compile as b1 and b2 will be promoted to int and the result is an int which can't be put into a byte without a cast. byte b1 = 10; long g = 20; byte b3 = g + b2; //Will not compile as b2 will be promoted to long and the result is a long which can't be put into a byte without a cast. EXCEPTION Compound operators: +=. -=, etc. b += 1; will compile because this is interpreted as: b = (byte) (b + 1); //Note the explicit casting. This is automatically done by the compiler for compound operators. Points to Remember: Division by zero or % by 0, for integral values throws an exception but for float and double, no exception occurs as the result is Float/Double.POSITIVE_INFINITY or Float/Double.NEGATIVE_INFINITY (For / ) OR Float/Double.NaN (for %) (NaN means: Not a Number)

% : Modulus operator. : Divide LHS by RHS and return the remainder. eg 32%7 = 4 ( 32 - 7*4 = 4), 32%-7 = 4 ( 32 - (-7 * -4) = 4), (-32)%7 = -4 ( -32 - (7*-4) = -4), -32%-7 = -4 ( -32 - (-7*4) = -4) You should observe that sign of the result is same as sign of the LHS. Floating point calculations can produce NaN (eg. 3.2%0 or square root of a negative number) or POSITIVE_INFINITY or NEGATIVE_INFINITY( division by zero). Float and Double wrapper classes have named constants for NaN and the two infinities.

41

NaNs cannot be compared with any thing. (Float.NaN == Float.NaN is false!!!) To test a NaN, use Float.IsNaN(f); or Double.isNaN(d); Infinities can be compared to give appropriate results. System.out.println( 1 + 2 + "3" ); // Prints 33 System.out.println( "1" + 2 + 3 ); // Prints 123 This is because, calculation is done from left to right.

Shift operators - (<<, >>, >>>) : << is used for shifting bits right to left. 0 bits are brought in from the right. Sign bit (MSB) is NOT preserved. Eg. int i = 0x80000002;; int k = i<<1; i => 1000 0000 0000 0000 0000 0000 0000 0010 -2147483646 k => 0000 0000 0000 0000 0000 0000 0000 0100 => 4 Notice that sign bit of k (leftmost bit) is 0 that means it is a positive no. In affect, k is i*2 but as -2147483646*2 doesn't fit into an int, overflow occured and only last 32 bits were put into k. >> is used for shifting bits left to right. The sign bit (the leftmost bit or the Most significant bit) keeps propagating towards right so Sign bit (MSB) IS preserved. Eg. int i = 0x80000002;; int k = i>>1; i => 1000 0000 0000 0000 0000 0000 0000 0010 -2147483646 k => 1100 0000 0000 0000 0000 0000 0000 0001 -1073741823 Notice that sign bit of k (leftmost bit) is 0 that means it is a negative no. In affect, k is i/2 . There is never an overflow with >> or >>> But notice what happens with -1: 1111 1111 1111 1111 1111 1111 1111 1111 -1 1111 1111 1111 1111 1111 1111 1111 1111 -1 -1 >> -1 is -1 >>> is same as >> except that sign is not preserved. 0 bits are inserted from the right instead of the sign bits. Eg. int i = 0x80000002;; int k = i>>>1; i => 1000 0000 0000 0000 0000 0000 0000 0010 -2147483646 k => 0100 0000 0000 0000 0000 0000 0000 0001 1073741825 Notice that sign bit of k (leftmost bit) is 0 that means it is a positive no. In affect, k is i/2 . Points to remember: For int, i >> k is actually i >> (K%32) and For long, i >> k is actually i >> (K%64) So, i>>34 is i>>2 and i = i >> 32 will not change i at all !!!

Comparison operators : <, <=, > , >= , instanceof <, <=, > , >= work as expected. instanceof operator checks the class of the object at LHS with the class name given at RHS. eg. obj instanceof java.util.Collection This will return true only if obj is refering to an object of class java.util.Collection or any subclass of java.util.Collection. If RHS is the name of an interface then LHS should point to an object of class that implements that interface. In object oriented terminology: obj instanceof java.util.Collection will return true if obj is an instance of java.util.Collection! . Ie. If obj points to java.util.Set, it will return true as a set is-a collection. Points to remember: LHS should be an object reference expression, variable or an array reference. RHS should be a class/interface. It throws compiler error if LHS & RHS are unrelated. You can also test for arrays.Eg.: obj instanceof Collection[] is legal.

42

Returns false if LHS is null, no exception is thrown. == for objects tests whether the 2 references point to the same memory location or not.

Bit-wise operators : (&, ^ and |) : & (AND) operator. | (OR) operator work as expected. ^ ( XOR) operator, returns 1 iff either and only one of LSH or RHS is 1/true. Points to remember: These can be applied to numeric as well as boolean operands. In case of boolean operands, & and | DO NOT SHORT CIRCUIT the expression.

Logical operators : && and || : Also known a Short Circuit operators. Points to remember: Can only be applied to booleans. These are also known as short circuiting operators because the RHS might not even be evaluated if the result can be determined only by looking at LHS. Ex. (false && m1() ) : Here, m1() will not be called as the expression will always be false no matter what m1() returns. So there is no point in calling m1(). Similarly, (true || m1()): This will always return true, no matter what m1() returns.

Assignment Operators: =, ?: and various compound assignment operators(like +=) Important Fact: You may know that other operators return a value. Eg. a + b returns the sum of a and b, a^b returns the XOR of a and b etc. What you may not know is the = operator also returns a value. I.e a = 3 assigns 3 to a but the whole expression (a=3) also returns a value which is equal to the RHS of the operator ie. 3. That's the reason b = a = 3; works. And that's the reason if( flag = true){} also works. Compound operators: a += b; is actually interpreted by the compiler as: a = (type of a) (a + b); So, byte b = 3; b = b+1; //won't work as b + 1 returns an int and explicit cast is needed. b += 1; // will work because it is interpreted as: b = (byte) (b+1); Note the cast. Ternary Operator: Possible uses: int a, b, c; // initialize the values somehow. boolean flag = ...//some way of setting it. a = flag? 10:20; a = (b == c) ? m1() : m2(); Here, it is important to know that it will only compile if the return types of m1() and m2 are compatible with the type of a. It won't compile if m1() or m2() return void. Points to remember: ?: does not evaluate both the RHS parameters. In the above example, if b==c, only m1() will be evaluated(called).

43

Assignment of reference variables copies the value of reference at RHS to LHS. So, in affect both the variables start pointing to same memory. Determine the result of applying the boolean equals(Object) method to objects of any combination of the classes java.lang.String, java.lang.Boolean, and java.lang.Object.

Consider the declarations: String s1, s2; //initialize them somehow Boolean bool1, bool2;//initialize them somehow boolean flag1, flag2; //initialize them somehow Object obj1; //initialize it somehow Points to remember: String implements (and thus overrides) equals() method of Object class. It returns true if both the String objects contain same sequence of character. Ex: s1.equals(s2); //will return true only if s1 and s2 contain same data. It doesn't matter whether s1 and s2 point to same object or not. Boolean also implements equals() method. bool1.equals(bool2) will return true only if bool1 and bool2 both contain same value. bool1.equals(flag1) will NOT compile. Object class's equals() method firsts checks whether both the objects are of same class or not. So, obj1.equals(bool1) will return false. If not, then it returns false. It then simply checks whether the two object references point to the same memory or not which is same as "==" operator.

In an expression involving the operators &, |, &&, ||, and variables of known values state which operands are evaluated and the value of the expression.

Points to Remember: && and || are short circuit operators. Examples: int i = 10; boolean flag = true; if( flag || ++i = 11) { ... } // Here, i will NOT be incremented. if( !flag && ++i = 11) { ... }// Here, i will NOT be incremented.

if( flag || m1() ) { ... } // Here, m1 will NOT be called. In the above cases, the outcome of the whole expression can be determined by just looking at the first part, so second part is NOT evaluated. Determine the effect upon objects and primitive values of passing variables into methods and performing assignments or other modifying operations in that method.

VERY IMPORTANT FACT: In java EVERY THING is passed by value. For primitive, it's value is passed (as expected). For object, the value of it's reference is passed. Read a detailed example explanation here : Pass by value

44

void changeObjects(String str, StringBuffer sb) { str = "123"; //makes the reference str to point to new string object containing "123". you are changing the reference here. str = str + "123"; //strings are immutable. It will create a new string containing "abc123". The original "abc" will remain as it is. sb.append("123"); //changes the actual object itself. you are NOT changing the reference here. } .... String s = "abc"; StringBuffer sb = new StringBuffer("abc"); changeString(s, sb); System.out.println(s); //Will still print "abc". System.out.println(sb); //Will still print "abc123".

45

Section 6 Overloading, Overriding, Runtime Type, and Object Orientation State the benefits of encapsulation in object oriented design and write code that implements tightly encapsulated classes and the relationships "is a" and "has a".

Encapsulation means the internal wirings (variables/fields/properties) of the class are not visible outside. Instead, the class provides accessor (getter and setter) methods for the properties it supports. In other words, have private fields and have public setters and getters. Consider the following declarations: public class GearBox { public void shiftGear(int gearNo){ ... } } public interface Movable{ } public class Car implements Movable { private GearBox gb = new GearBox(); } public class SportsCar extends Car { } In the above situation: .SportsCar is-a Car ( because SportsCar extends Car ) .Car has-a GearBox ( because Car has a variable of class GearBox ) .SportsCar has-a GearBox ( because SporstCar is a Car and Car has a GearBox ) .Car and SportsCar is-a Movable (because Car implements Movable and SportsCar extends Car) Although, this is strictly an is-like-a relationship but still can be clubbed together with is-arelationship. Write code to invoke overridden or overloaded methods and parental or overloaded constructors; and describe the effect of invoking these methods.

Points to remember: . Overloaded methods are entirely independent methods. Two overloaded methods behave as if they were two methods with different names. Method name is NOT important, it's the signature (ie. method name + parameterlist) that governs the behavior and overloaded methods have different signatures.

Write code to construct instances of any concrete class including normal top level classes, inner classes, static inner classes, and anonymous inner classes.

46

Section 7 Threads Write code to define, instantiate, and start new threads using both java.lang.Thread and java.lang.Runnable.

Two ways to create a new thread: 1. Have a class implement the Runnable interface. Ex: class X implements Runnable { public void run() //must implement this method. { ... } } Now, create a Thread object : X obj = new X(); //Not a new thread yet. Thread t = new Thread( obj ); //This creates a new Thread. It's not started yet. 2. Have a class extend from Thread class. Ex: class X extends Thread { public void run(){ ... } //should implement this method to do something useful. } Now, create a Thread object : Thread t = new X(); Points to remember: A thread is started only when you call start() on a Thread object. In above example, t.start() will start the newly created thread. Calling t.run() DOES NOT start a new thread. It will execute in the same thread just like any other method. Method run() of thread class is not abstract, so not implementing it in a subclass it not a problem. But the Thread class's run method doesn't do anything. Thread is created only by instantiating Thread or a subclass of Thread Instantiating objects of classes that implement Runnable does not create new thread.

Recognize conditions that might prevent a thread from executing.

Methods that will definitely stop/pause a running thread:

47

sleep() : Does not release the locks (if any). wait() : should have the lock before calling this method. It releases the lock and waits till somebody calls a notify/notifyAll. stop() : releases all the locks. Deprecated. suspend() : DOES NOT release any locks. Deprecated.

Methods that MAY or MAY NOT stop/pause a running thread: yield() : If there are no threads of the same priority, this call is ignored setPriority() : even if you lower the priority, the OS may not preempt this thread. notify/notifyAll() : These methods simply release the locks and other thread which are waiting on them become "read to run". But CPU may or may not schedule them. Points to note : join() : It will pause the current thread till the thread on which it has called join, dies. Write code using synchronized, wait, notify, or notifyAll, to protect against concurrent access problems and to communicate between threads. Define the interaction between threads and between threads and object locks when executing synchronized, wait, notify, or notifyAll.

Important Facts: A "lock" is a part of any object. One object has only one lock but it may be acquired multiple times (but only by the same thread which already has got it for the first time). If a thread acquires the lock twice then it should release it twice. For static blocks (where there is no instance), there is a class object for that class which has a lock. It's the thread (not a Thread object but the flow of control) that 'acquires' lock. Understand the distinction between a Thread object and a thread. Thread object is just another object. A thread is the flow of control that executes the code. You need a Thread object to create a thread. As there is only one lock for one object, only one thread can get the lock for an object at any given time.

This is very important topic which you should read from any good book like Thinking in Java. Points to remember: The thread that is calling wait/notify/notifyall on an object MUST have the lock of that object otherwise an IllegalMonitorState exception will be thrown. In other words, acquiring lock of one object and calling notify() on another DOES NOT WORK. When a thread tries to enter a synchronized method/block, it waits till it acquires the lock for the object whose method it is trying to enter. For static methods, it waits for the class object's lock. A thread dies when it's run method ends (or if the stop method, which is deprecated) is called. It cannot be restarted. Methods of a Thread object can be called anytime as if it were just another normal object. Except start() which can be called only once. Calling start() creates a new thread of execution.

48

A thread spawned by a daemon thread is a daemon thread but you can change it by calling setDaemon(false). A thread can be made a daemon thread by calling setDaemon(true) method. This method must be called before the thread is started, otherwise an IllegalThreadStateException will be thrown. Threads have priorities. Thread class defines the int constants MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY. Their values are 10, 0 and 5 but you should use the constant names instead of the values. A newly created thread has the same priority as the thread which created it. You can change it by calling setPriority(). Which thread is scheduled when depends on the JVM and platform. So, you can NEVER say for sure about which thread would be running at at what time. Ie. If you start 2 threads you can't say anything about their execution schedule. And your code should not depend on any such assumptions. wait() and sleep() must be enclosed in a try/catch block as they throw InterruptedException. A thread can obtain multiple locks on the same object or multiple objects. If a thread acquires a lock for the same object twice, it should release it twice otherwise the object will remain locked. A thread owning the lock of an object can call other synchronous methods on the same object. In a sense, it is acquiring the same lock more than once. Synchronized methods can be overridden to be non-synchronized. But it does not change the behavior for the super class's method. Beware of deadlock: Consider this situation: Thread1 gets the lock for object1 and tries to acquire the lock for object2. Just before it could get the lock for obj2, the OS preempts this thread and runs another thread t2. Now t2 gets the lock for obj2 (which was available as T1 was stopped just before it could acquire the lock) and then tries to get the lock for Object1 (which was already acquired by T1). Here, you can see that T1 is waiting for obj2's lock which is acquired by T2, and T2 is waiting for obj1's lock which is accuired by T1. Neither of the threads is able to proceed. This is a Deadlock. Java does not provide any mechanism to detect, avoid or solve a deadlock. You must program so that deadlocks don't happen at runtime.

49

You might also like