java-Unit-3
java-Unit-3
UNIT-III
INHERITANCE :
The mechanism of deriving a new class from an old one is called inheritance. The old class is known as the
base class or super class or parent class and the new one is called the subclass or derived class or child class.
The inheritance allows subclass to inherit all the variables and the variables and methods of their parent
classes. Inheritance has following forms.
1. Single Inheritance
2. Multiple Inheritance
3. Hierarchical Inheritance
4. Multilevel Inheritance
Defining a Subclass
A subclass is defined as follows:
class subclassname extends superclass name
{
Variables declaration;
Methods declaration;
}
The keyword extends signifies that the properties of the supecalssname are extended to the subclassname.
The subclass will now contain its own variables and methods as well as those of the supercalsss.
//Program: Application of single inheritance
class Room
{
int length;
int breadth;
Room(int x, int y)
{
length= x;
breadth= y;
}
int area()
{
return ( length * breadth);
}
}
class InheritTest
{
public static void main(String args [])
{
BedRoom r1 = new BedRoom(14, 12, 10);
int area1= r1.area();
int volume1 = r1.volume();
System.out.println("Area1 =" + area1);
System.out.println("Volume=" + volume1);
}
Output:
Area1= 168
Volume = 1680
The constructor in the derived class uses the super keyword to pass values that are required by the base
constructor. The statement
BedRoom r1 = new BedRoom (14, 12, 10);
calls first the BedRoom constructor method, which in turn calls the Room constructor method by using the
super keyword.
Subclass Constructor
A subclass constructor is used to construct the instance variables of both the subclass and the superclass. The
subclass constructor uses the keyword super to invoke the constructor method of the superclass.
Using super
Whenever a subclass needs to refer to its immediate superclass, it can do so by use of the keyword super.
super has two general forms. The first calls the superclass’ constructor. The second is used to access a
member of the superclass that has been hidden by a member of a subclass.
This second form of super is most applicable to situations in which member names of a subclass hide
members by the same name in the superclass.
Consider this simple class hierarchy:
// Using super to overcome name hiding.
class A {
int i;
}
// Create a subclass by extending class A.
class B extends A {
int i; // this i hides the i in A
B(int a, int b) {
super.i = a; // i in A
i = b; // i in B
}
void show() {
System.out.println("i in superclass: " + super.i);
System.out.println("i in subclass: " + i);
}
}
class UseSuper {
public static void main(String args[]) {
B subOb = new B(1, 2);
subOb.show();
}
}
This program displays the following:
i in superclass: 1
i in subclass: 2
Superclass
B
Intermediate superclass
C
Subclass
The class A serves as a base class for the derived class B which in turn serves as a base class for the derived
class C. The chain ABC is known as inheritance path.
A derived class with multilevel base class is declared as follows.
class A
{
………….
}
class B extends A
{
………….
}
class C extends B
{
………….
}
This process may be extended to any number of levels.
Hierarchical Inheritance
Derivation of more than one class from a single base class is termed as hierarchical inheritance. This is a
very common form of inheritance in practice. The rules for defining such classes are the same as in single
inheritance. The pictorial representation of hierarchical inheritance is as follows:
}
class CallingCons {
public static void main(String args[]) {
C c = new C();
}
}
The output from this program is shown here:
Inside A’s constructor
Inside B’s constructor
Inside C’s constructor
Overriding Methods
It is possible by defining a method in the subclass that has the same name, same arguments and same return
type as a method in the superclass. Then when that is called the method defined in the subclass is invoked
and executed instead of the one in the superclass. This is known as overriding.
Program: Illustration of method overriding
class Super
{
int x;
Super(int x)
{
this.x=x;
}
void display ()
{
System.out.println("Super x=" +x);
}
}
void display ()
{
System.out.println("Super x=" +x);
System.out.println("Sub y=" +y);
}
class OverrideTest
{
public static void main(String args[])
{
Sub s1 = new Sub(100, 200);
s1.display();
}
}
Making a method final ensures that the functionality defined in this method will never be altered in any way.
Similarly the value of the final variable can never be changed. Final variables behave like class variables
and they do not take any space on individual object of the class.
Final Classes
Sometimes we may like to prevent a class from being further subclasses for security reason. If we write the
final keyword infront of a class name in the class declaration then that class cannot be inherited i.e., we
cannot create sub classes from that class. This is written as follows:
final class A {
// ...
}
// The following class is illegal.
finalizer () method
We have seen that constructors are used to initialize an object when it is declared. This process is known as
initialization. Similarly java supports a concept called finalization, which just opposite to initialization. The
garbage collector is program which frees up memory resources used by the objects. But objects may hold
other non object resources such as file descriptors or window system fonts. The garbage collector cannot
free these resources. In order to free these resources we must use the finalizer method. It is similar to
destructors in C++.
The finalizer method is simply finalize () and can be added to any class. The finalize method should
explicitly define the tasks to be performed.
Here is a simple example of a class with an abstract method, followed by a class which
implements that method:
// A Simple demonstration of abstract.
abstract class A {
abstract void callme();
// concrete methods are still allowed in abstract classes
void callmetoo() {
System.out.println("This is a concrete method.");
}
}
class B extends A {
void callme() {
System.out.println("B's implementation of callme.");
}
}
class AbstractDemo {
public static void main(String args[]) {
B b = new B();
b.callme();
b.callmetoo();
}
}
Notice that no objects of class A are declared in the program. As mentioned, it is not possible to instantiate
an abstract class. One other point: class A implements a concrete method called callmetoo( ). This is
perfectly acceptable.
PACKAGES
A Java package is a set of classes and interfaces which are grouped together. The grouping is usually done
according to functionality. In fact, packages act as container for classes.
The classes contained in the packages of other programs can be easily reused.
In packages, classes can be unique compared with classes in other packages. That is, two classes in two
different packages can have the same name.
Packages provide a way to hide classes thus preventing other programs or packages from accessing
classes that are meant for internal use only.
Packages provide a way for separating design from coding. First we can design classes and decide their
relationships and then we can implement the java code needed for the methods. It is possible to change
the implementation of any method without affecting the rest of the design.
Defining a Package
To create a package is quite easy: simply include a package command as the first statement in a Java source
file. Any classes declared within that file will belong to the specified package. The package statement
defines a name space in which classes are stored. If you omit the package statement, the class names are put
into the default package, which has no name. While the default package is fine for short, sample programs, it
is inadequate for real applications. Most of the time, you will define a package for your code.
Java uses file system directories to store packages. For example, the .class files for any c More than one file
can include the same package statement. The package statement simply specifies to which package the
classes defined in a file belong.lasses you declare to be part of MyPackage must be stored in a directory
called MyPackage.
You can create a hierarchy of packages. To do so, simply separate each package name from the one above it
by use of a period. The general form of a multileveled package statement is shown here:
package pkg1[.pkg2[.pkg3]];
Apackage hierarchy must be reflected in the file system of your Java development system. For example, a
package declared as
package java.awt.image;
A Short Package Example
Keeping the preceding discussion in mind, you can try this simple package:
// A simple package
package MyPack;
class Balance {
String name;
double bal;
Balance(String n, double b) {
name = n;
bal = b;
}
void show() {
if(bal<0)
System.out.print("--> ");
System.out.println(name + ": $" + bal);
}
}
class AccountBalance {
public static void main(String args[]) {
Balance current[] = new Balance[3];
current[0] = new Balance("K. J. Fielding", 123.23);
current[1] = new Balance("Will Tell", 157.02);
current[2] = new Balance("Tom Jackson", -12.33);
for(int i=0; i<3; i++) current[i].show();
}
}
{
System.out.println("Class B");
System.out.println("m= "+m);
}
}
class PackageTest
{
public static void main(String args[])
{
ClassA obA= new ClassA();
ClassB obB= new ClassB();
obA.displayA();
obB.displayB();
}
Output:
Class A
Class B
m= 10
Access Protection
Packages add another dimension to access control. As you will see, Java provides many levels of protection
to allow fine-grained control over the visibility of variables and methods within classes, subclasses, and
packages It is possible to inherit all the members of a class by a subclass using the keyword extends. The
variables and methods of a class are visible everywhere in the program. However, it may be necessary in
some situations we may want them to be not accessible outside. We can achieve this in Java by
applying visibility modifiers to instance variables and methods. The visibility modifiers are also known
as access modifiers. Access modifiers determine the accessibility of the members of a class.
Java provides three types of visibility modifiers: public, private and protected. They provide different
levels of protection as described below.
Public Access: Any variable or method is visible to the entire class in which it is defined. But, to make a
member accessible outside with objects, we simply declare the variable or method as public. A variable or
method declared as public has the widest possible visibility and accessible everywhere.
Friendly Access (Default): When no access modifier is specified, the member defaults to a limited version
of public accessibility known as "friendly" level of access. The difference between the "public" access and
the "friendly" access is that the public modifier makes fields visible in all classes, regardless of their
packages while the friendly access makes fields visible only in the same package, but not in other packages.
Protected Access: The visibility level of a "protected" field lies in between the public access and friendly
access. That is, the protected modifier makes the fields visible not only to all classes and subclasses in the
same package but also to subclasses in other packages
Private Access: private fields have the highest degree of protection. They are accessible only with their own
class. They cannot be inherited by subclasses and therefore not accessible in subclasses. In the case of
overriding public methods cannot be redefined as private type.
Private protected Access: A field can be declared with two keywords private and protected together. This
gives a visibility level in between the "protected" access and "private" access. This modifier makes the fields
visible in all subclasses regardless of what package they are in. Remember, these fields are not accessible by
other classes in the same package.
Importing Packages
We have already know, how a class can be imported from a package and used in a program. The import
statement is used to search a list of packages for a particular class. In the case of user defined package also,
for accessing a particular class we will use the import statement. The general form of import statement for
searching a class is as follows:
import package1 [.package2] [.package3].Classname;
Here pakcage1 is the name of the top level package, package2is the name of the package that is inside the
package1, and so on.
Note that the statement must end with a semicolon (;). The import statements and must appear at the top of
the file, before any class declaration. Multiple import statements are allowed. Examples:
import java. awt. Color; imports the class Color and therefore the class name can now be directly used
in the program.
import java. awt. *; imports all classes of java. awt package
INTERFACES
“An interface is a collection of methods and variables like a class but it is not a class. The difference
between a class and interface is that interface defines only abstract methods and final fields. This means
that interfaces do not specify any code to implement these methods and data fields contain only constants.
Therefore it is the responsibility of the class that implements an interface to define the code for
implementation of these methods.”
Defining an Interface
The syntax for defining an interface is very similar to that for defining a class, which is shown below:
interface interfaceName
{
variables declaration;
methods declaration;
}
Here interface is the key word and interfacename is any valid java identifier. Variables are declared as
follows:
Note that all variables are declared as constants. Methods declarations will contain only a list of methods
without anybody statements. Example:
An Example of interface definition that contains two variables and one method
interface Area
{
final static float pi =3.142F;
float compute (float x, float y);
void show();
}
Implementing Interfaces
Interfaces are used as superclasses whose properties are inherited by classes. It is therefore necessary to
create a class that inherits the given interface. This is done as follows
class Classname extends superclass implements intefacename1, intefacename1……..
{
body of classname
}
Here the classname implements the interface interfacename.
method through one of these references, the correct version will be called based on the actual instance of the
interface being referred to. This is one of the key features of interfaces. Followingg exaample demostates
this.
Program: Implementing interfaces and Accessing Implementations Through Interface References
class Rectangle implements Area
{
public float compute(float x, float y)
{
return(x *y);
}
}
class InterfaceTest
{
public static void main(String args[])
{
Rectangle rect= new Rectangle();
Circle cir = new Circle();
Area a; // iterface object
a=rect;
System.out.println("Area of Rectangle = "+a.compute(10, 20)); //a refers to rect object
a=cir;
System.out.println("Area of Rectangle = "+a.compute(10,0)); //a refers to cir object
}
}
Output:
Area of Rectangle = 200.0
Area of Rectangle = 314.0
EXCEPTION HANDLING
Exception-Handling Fundamentals
Runtime error of java program is known as exception. When an exceptional condition arises, an object
representing that exception is created and thrown in the method that caused the error. That method may
choose to handle the exception itself, or pass it on. Either way, at some point, the exception is caught and
processed. Exceptions can be generated by the Java run-time system, or they can be manually generated by
your code.
If the exception object is caught and handled properly, the interpreter will display an error message as shown
in the output of program and will terminate the program. If we want the program to continue with the
execution of the remaining the code, then we should try to catch the exception object thrown by the error
condition and then display an appropriate message for taking corrective actions. This task is known as
exception handling.
Java exception handling is managed via five keywords: try, catch, throw, throws, and finally. Briefly, here
is how they work. Program statements that you want to monitor for exceptions are contained within a try
block. If an exception occurs within the try block, it is thrown. Your code can catch this exception (using
catch) and handle it in some rational manner. System-generated exceptions are automatically thrown by the
Java run-time system. To manually throw an exception, use the keyword throw. Any exception that is
thrown out of a method must be specified as such by a throws clause. Any code that absolutely must be
executed after a try block completes is put in a finally block.
The purpose of exception handling mechanism is to provide a means to detect and report an “exceptional
circumstances” so that appropriate action can be taken. The mechanism suggests incorporation of separate
error handling code that performs the following tasks:
The error handling code basically consists of two segments, one to detect errors and to throw exception and
the other to catch exception and to take appropriate actions.
Java uses a keyword try to preface a block of code that is likely to cause an error condition and “throw” an
exception. A catch block defined by the keyword catch “catches” the exception “thrown” by the try block
and handles it appropriately. The catch block is added immediately after the try block. The following
example illustrates the use of simple try and catch statements:
-----------------
-----------------
try
{
Statement: // generates an exception
}
catch (Exception_type e)
{
Statement: // processes the exception
}
-----------------
-----------------
The try block can have one or more statements that could generate an exception. If anyone statement
generate an exception, the remaining statement in the block are skipped and execution jumps to the catch
block that is placed next to the try block.
The catch block to can have one or more statement that are necessary to processes the execution. Remember
that every try statement should be followed by at least one catch statement; otherwise compilation error will
be occurred.
Note that the catch statement works like a method definition. The catch definition is passed a single
parameter, which is reference to the exception object thrown (by the try block). If the catch parameter
matches with the type of exception object, then the exception is caught and statement in the catch block will
be executed. Otherwise, the exception is not caught and the default exception handler will cause the
execution to terminate
Exception Types
All exception types are subclasses of the built-in class Throwable. Thus, Throwable is at the top of the
exception class hierarchy. Immediately below Throwable are two subclasses that partition exceptions into
two distinct branches. One branch is headed by Exception. This class is used for exceptional conditions that
user programs should catch. This is also the class that you will subclass to create your own custom exception
types. There is an important subclass of Exception, called RuntimeException. Exceptions of this type are
automatically defined for the programs that you write and include things such as division by zero and invalid
array indexing.
Uncaught Exceptions
Before you learn how to handle exceptions in your program, it is useful to see what happens when you don’t
handle them. This small program includes an expression that intentionally causes a divide-by-zero error:
class Exc0 {
public static void main(String args[]) {
int d = 0;
int a = 42 / d;
}
}
When the Java run-time system detects the attempt to divide by zero, it constructs a
new exception object and then throws this exception. This causes the execution of Exc0 to stop, because
once an exception has been thrown, it is not caught.
catch (ArithmeticException e) {
System.out.println("Exception: " + e);
a = 0; // set a to zero and continue
}
When this version is substituted in the program, and the program is run, each divide-byzero error displays
the following message:
Exception: java.lang.ArithmeticException: / by zero
} catch(ArithmeticException e) {
System.out.println("Divide by 0: " + e);
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Array index oob: " + e);
}
System.out.println("After try/catch blocks.");
}
}
This program will cause a division-by-zero exception if it is started with no commandline arguments, since a
will equal zero.
finally Statement
finally creates a block of code that will be executed after a try/catch block has completed and before the
code following the try/catch block. The finally block will execute whether or not an exception is thrown. If
an exception is thrown, the finally block will execute even if no catch statement matches the exception. Any
time a method is about to return to the caller from inside a try/catch block, via an uncaught exception or an
explicit return statement, the finally clause is also executed just before the method returns. This can be
useful for closing file handles and freeing up any other resources that might have been allocated at the
beginning of a method with the intent of disposing of them before returning. The finally clause is optional.
However, each try statement requires at least one catch or a finally clause. Here is an example program that
shows three methods that exit in various ways, none without executing their finally clauses:
// Demonstrate finally.
class FinallyDemo {
// Through an exception out of the method.
static void procA() {
try {
System.out.println("inside procA");
throw new RuntimeException("demo");
} finally {
System.out.println("procA's finally");
}
}
// Return from within a try block.
static void procB() {
try {
System.out.println("inside procB");
return;
} finally {
System.out.println("procB's finally");
}
}
// Execute a try block normally.
static void procC() {
try {
System.out.println("inside procC");
} finally {
System.out.println("procC's finally");
}
}
public static void main(String args[]) {
try {
procA();
} catch (Exception e) {
System.out.println("Exception caught");
}
procB();
procC();
}
}
Here is the output generated by the preceding program:
inside procA
procA’s finally
Exception caught
inside procB
procB’s finally
inside procC
procC’s finally
Table 10-2 lists those exceptions defined by java.lang that must be included in a method’s throws list if that
method can generate one of these exceptions and does not handle it itself. These are called checked
exceptions. Java defines several other types of exceptions that relate to its various class libraries.
MULTI THREADING
Introduction
Multithreading is a conceptual programming concept where a program is dividing into two or more
subprograms (Process), which can be implemented at the same time in parallel. A multithreaded program
contains two or more parts can run concurrently. Each part of such a program is called a thread, and each
thread defines a separate path of execution. A process consists of the memory space allocated by the
operating system that can contain one or more threads. A thread cannot exist on its own; it must be a part of
a process.
In most of our computers we have only one processor and therefore in reality the processor is doing only one
thing at a time. However the processor switches between the processes so fast that it appears to the human
beings that all of them are being done simultaneously.
A thread is similar to a program that has single flow of control. It has a beginning, a body, and an end, and
executes commands sequentially.
A unique property of Java is its support for multithreading. That is java enables us to use multiple flows of
control in developing programs. Each flow of control may be thought of as a separate tiny program known
as a thread.
Uses of Multiprogramming
1. It enables programmers to do multiple things at one time. They can divide a long program into
threads and execute them in parallel.
2. Threads are extensively used in java enabled browsers such as HotJava. These browsers can
download a file to the local computer display a web page in the window output another Web page to
a printer and so on.
Creating Threads
Threads are implemented in the form of objects that contain a method called run(). The run() method is the
heart and soul of any thread. It makes up the entire body of a thread and is the only method in which the
thread’s behavior can be implemented. A typical run() method would appear as follows:
The run() method should be invoked by an object of the concerned thread. This is achieved by creating the
thread and initiating it with help of another method called start().
There are two ways to create threads in java
1. By created a thread class: Define a class that extend Thread class and override its run() method
with the code required by the thread.
2. By converting a class to a thread: Define a class that implements Runnable interface. The
Runnable interface has only one method, run() that is to be defined with the code to be executed by
the thread.
The approach to be used depends on what the class we are creating requires. If it requires to extend another
class, then we have no choice but to implement the Runnable interface since java class cannot have two
super classes.
When we start the new thread, Java calls the Thread’s run() method, so it is the run() where all the action
takes place.
The first line instantiates a new object of class MyThread. Note that this statement just creates the object.
The thread that will run this object is not at running. The thread is in a newborn state.
The second line calls the start() method causing the thread to move into the runnable state. Then, the Java
runtime will schedule the thread to run by invoking its run( ) method. Now, the thread is said to be in the
running state.
The main thread dies at the end of its main method. However, before it dies, it creates and starts all the three
threads A, B, and C. the statement like
New A( ).start( );
in the main thread. This is just a compact way of starting a thread. This is equivalent to:
A threadA = new A( );
threadA.start( );
Immediately after the thread A is started, there will be two threads running in the program: the main thread
and the thread A. The start( ) method returns back to the main thread immediately after invoking the run( )
method, thus allowing the main thread to start the thread B.
}
System.out.println("Exiting the thread B ");
}
}
class threadtest
{
public static void main(String args[])
{
new A().start();
new B().start();
new C().start();
}
}
Similarly, it starts C thread. By the time the main thread has reached the end of its main method, there are a
total of four separate threads running in parallel.
We have simply initiated three new threads and started them. We did not hold on to them any further. They
are running concurrently on their own. Note that the outputs from the threads are not especially sequential.
They do not follow any specific order. They are running independently of one another and each executes
Stopping a Thread
Whenever we want to stop a thread from running further, we may do so by calling its stop( ) method, like
aThread.stop( );
This statement causes the thread to move to the dead state. A thread will also move to the dead state
automatically when it reaches the end of its method. The stop( ) method may be used when the premature
death of a thread is desired.
Blocking a Thread
A thread can also be temporarily suspended or blocked from entering into the runnable and subsequently
running state by using either of the following thread methods.
sleep( ) //blocked for a specified time
suspend( ) //blocked until further order
wait( ) //blocked until certain conditions occurs
These methods cause the thread to go into the blocked (or not-runnable) state. The thread will return to the
runnable state when the specified time is elapsed in the case of sleep( ),the resume( ) method is invoked in
the case of suspend( ),and the notify( ) method is called in the case of wait( ).
If scheduled, it moves to the runnable state. If we attempt to use any other method at this stage, an exception
will be thrown.
Runnable State
The state means that the thread is ready for execution and is waiting for the availability of the processor.
That is, the thread has joined the queue of threads that are waiting for execution. If all threads have equal
priority, then they are given time slots for execution in round robin fashion, i.e., first-come, first-serve
manner. The thread that relinquishes control joins the queue at the end and again waits for its turn. This
processor of assigning time to threads is known as time-slicing.
However, if we want a thread to relinquish control to another thread to equal priority before its turn comes,
we can do so by using the yield( ) method.
Running State
Running means that the processor has given its time to the thread for its execution. The thread runs until it
relinquishes control on its own or it is preempted by a higher priority thread. A running thread may
relinquish its control in one of the following situations.
1. It has been suspended using suspend( ) method. A suspended thread can be revived by using the
resume( ) method. This approach is useful when we want to suspend a thread for some time due to
certain reason, but do not want to kill it.
2. It has been made to sleep. We can put a thread to sleep for a specified time period using the method
sleep(time) where time is in milliseconds. This means that the thread is out of the queue during this
time period. The thread re-enters the runnable state as this time period elapsed.
3. It has been told to wait until some event occurs. This done using the wait( ) method. The thread can
been scheduled to run again using the notify( ) method.
Blocked State
A thread is said to be blocked when it is prevented from entering into the runnable state and subsequently the
running state. This happens when thread is suspended, sleeping, or waiting in order to satisfy some
requirements. A blocked thread considered “not runnable” but not dead therefore fully qualified to run again.
Dead State
Every thread has a life cycle. A running thread ends its life when it has completed execution its run( )
method. It is a natural death. However we can kill it by sending a stop message to it at any state thus causing
a premature death to it. A thread can be killed as soon it is born, or while it is running, or even when it is in
“not runnable” (blocked) condition.
{
for (int i=1;i<=5;i++)
{
if (i==1)
yield();
System.out.println("\n From Thread A : i = "+i);
}
{
for (int j=1;j<=5;j++)
{
System.out.println("\n From Thread B : j = " + j);
if (j==3)
stop();
}
System.out.println("Exit from B");
}
}
{
for (int k=1;k<=5;k++)
{
System.out.println("\n From Thread C : k = "+k);
if (k==1)
try
{
sleep(1000);
}catch(Exception e){}
}
class ThreadMethods
{
public static void main(String args[])
{
A threadA = new A();
B threadB = new B();
C threadC = new C();
Program uses the yield ( ) method in a thread A at the iteration i=1. Therefore, the thread A, although
started first, has relinquished its control to the thread B. The stop( ) in the thread B has killed after
implementing the for loop only three times. Note that it has not reached end of run( ) method. The thread C
started sleeping after executing for loop only once. When it woke up (after 1000 milliseconds), the other two
thread have already completed their runs and therefore was running alone. The main thread died much
earlier than the other three threads.
class RunnableTest
{
public static void main(String args[])
{
X runnable = new X();
Thread threadX = new Thread(runnable);
threadX.start();
System.out.println("End of main Thread");
}
}
Output: