What Are The Potential Trips/traps in SCJP Exam?: Collection Is An Interface Where As Collections Is A Helper Class
What Are The Potential Trips/traps in SCJP Exam?: Collection Is An Interface Where As Collections Is A Helper Class
1
2
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 char c1 = '\u0057'
o char c1 = 'w'
o char c1 = 87
o char c1 = '\r'
• 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).
• 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.
• A valid overload differs in teh number or types of arguments. Difference is return type only is not
a valid overload.
• Mmember inner classes cannot have the same name as enclosing class, but they CAN subclass the
enclosing class.
3
• 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:
• If you have a sycnhronized method in a class, a subclass with an overriding method does not have
to declare it to be synchronized.
• 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.
• -(i) = ~(i) + 1
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.
• 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.
4
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().
• 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,
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
5
• 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
• 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.
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.
• A constructor does not declare any return type, not even a void.
• You cannot pass void as a parameter to a method, e.g., void method (void) is wrong.
6
and are usually used for being passed to a method as a parameter.
• It is not possible to use a break statement inside an if block. Break statements can only be used for
o Do-while
o While
o For
o Labelled blocks
o 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.
• 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.
• Package member classes, local classes and anonymous classes cannot be declared to be static.
• 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.
• 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.
7
• String comparisons for strings created at runtime, return false, e.g., if ja="ja" and va = "va" and
java="java"
• length is a field (instance variable) for an array, but a string length() is a method.
• Math.round (-4.7) = -5
• For Math.round()
• 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.
Vector v = new Vector (5, 10), where 5 is the initial capacity of the
vector and 10 is the capacity increment.
8
• 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.
-infinity -> -ve nos/fractions -> -0.0 -> 0.0 -> +0.0 -> +ve nos/fractions
-> +infinity
• 2 + 3 + "" = 5
• 2 + "" + 3 = 23
• " + 2 + 3 = 23
• You can't assign a 2nd value to a final variable. You CAN assign the value like this:
MAX_INT = 30;
• 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.
• If i = 3, then
• The array-size specifier must be an integral type, you can't use long, etc.
9
• StringBuffer class does not ovverride equals method. So, the equals method returns false when
passed two different StringBuffer objects, containing the same values.
• 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().
• 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 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).
• Overriding methods cannot throw checked exceptions not thrown by overridden methods, but they
CAN throw unchecked exceptions not thrown by overridden methods, like
ArrayIndexOutofBoundsException.
• 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 order of the exceptions specified by a method should be more specific exception followed by
less specific exception.
o A finally block.
• 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.
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.
• 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 by Koray Guclu
Top-Level Class
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.
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.
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 top-
level 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.
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. class Outer {
2. //class Cinner {interface IInner {}; } //Error. Inner class can't have static
members
4. }
5.
6. interface IOuter {
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 top-
level class. If a static modifier is used, there is no requirement for an enclosing class, like a top-
level 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.
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.
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.
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
Declaration As static class As non-static In block with non- In block with non-static
Context member class member static context context
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 Only non-static
non-static non-static
members
15
Can use extends Yes Yes Yes No
or implements
clauses?
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.
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.
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.
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
o 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.
If the suit variable takes on another value and assertions are enabled, the assert
will fail and an AssertionError will be thrown.
o 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
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
19
By convention, preconditions on public methods are enforced by explicit checks that throw
particular, specified exceptions.
o Further, the assert construct does not throw an exception of the specified type. It can
throw only an AssertionError.
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:
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);
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:
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!)
o it also reduces class file size, possibly leading to improved class loading performance.
o 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:
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.
o no arguments
Enables or disables assertions in all classes except system classes.
o packageName...
Enables or disables assertions in the named package and any subpackages.
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:
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:
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.
23
-da:<packagename>... Java –da:pkg0... Disable assertions in package
pkg0
24
Assertion do’s Assertion don’ts
Do use to check conditions at the end of any Don’t use to enforce public usage patterns or
kind of method protocols
Do use to check for conditional cases that Don’t use to enforce a property of a piece of user
should never happen supplied information
Do use to check for conditional cases that Don’t use as a shorthand for if (something)
should never happen, even if you’re really error();
sure they can never happen
Do use to check related conditions at the Don’t use as an externally controllable conditional
start of any method
Do use to check things in the middle of a Don’t use as a check on the correctness of your
long lived loop 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
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.
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'.
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:
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.
• A member class is a class 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
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.
30
Section 2 FLOW CONTROL AND EXCEPTION HANDLING
• Write code using if and switch statements and identify legal argument types for these
statements.
Rules:
31
1. 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.
2. In a chained if : else-if : else construct, the 'else' attaches to the nearest 'if' above it. So, the above
construct is equiv. to:
3.
4. if(flag)
5. {
6. System.out.println("first if");
7. }
8. else
9. {
10. if(flag == bool)
11. {
12. System.out.println("first else-if");
13. }
14. else
15. {
16. if( bool )
17. {
18. System.out.println("second else if");
19. }
20. else
21. {
22. System.out.println("last else");
23. }
24. }
25. }
26.
-------------------------------------------------------------------
Consider the following switch block:
}
}
32
Rules:
1. '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.
2. The case value should be a compile time constant. So, //6 is not valid.
3. The case value should 'fit' into the type of the case variable. Ex. if 'i' is of type byte then //2 is
invalid.
4. '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.
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 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.
Some Points to Remember:
• 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.
• 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 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.
• Package statement (if exists) should be the first statement. (comments before it are ok!). Next
should be the import statements. (if any).
• 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.
• 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:
37
System.out.println("Hello, World!");
}
}
Points to remember:
• args will NEVER be null.
• 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.
• 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
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
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.
1. Unary operators.
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
expression’s value. (2’s 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.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!!!)
>> 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:
• 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:
• In case of boolean operands, & and | DO NOT SHORT CIRCUIT the expression.
• 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.
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.
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.
• 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:
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.
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.
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.
• Instantiating objects of classes that implement Runnable does not create new 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.
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