Module 2-1
Module 2-1
There are two types of modifiers in Java: access modifiers and non-access modifiers. The access modifiers in Java
specify the accessibility or scope of a field, method, constructor, or class. We can change the access level of fields,
constructors, methods, and class by applying the access modifier on it.
There are four types of Java access modifiers:
1. Private: The access level of a private modifier is only within the class. It cannot be accessed from outside the class.
2. Default: The access level of a default modifier is only within the package. It cannot be accessed from outside the
package. If you do not specify any access level, it will be the default.
3. Protected: The access level of a protected modifier is within the package and outside the package through child
class. If you do not make the child class, it cannot be accessed from outside the package.
4. Public: The access level of a public modifier is everywhere. It can be accessed from within the class, outside the
class, within the package and outside the package.
Access Modifier within class within package outside package by outside package
subclass only
Private Y N N N
Default Y Y N N
Protected Y Y Y N
Public Y Y Y Y
Module 2
Inheritance
Inheritance in Java is a mechanism in which one object acquires all the properties & behaviors of the parent object.
The idea behind inheritance is that you can create new classes that are built upon existing classes and can reuse the
methods. To inherit a class java uses extends keyword.
Example-
class A {
int i,j;
void showij() {
System.out.println(“i and j : “+i+” “+j);
}
}
class B extends A {
int k;
void showk() {
System.out.println(“k: “+k);
}
void sum() {
System.out.println(“i+j+k:” +(i+j+k));
}
}
Terms Used in Inheritance-
Parent Class/ Superclass- The class from which a class inherits methods and attributes is known as parent class.
Child Class/ Subclass- The class that inherits some other class methods and attributes is known as child class.
Class A
Class B
Single Inheritance
Example-
class Animal {
void eat() {
System.out.println(“Eating”);
}
}
class Dog extends Animal {
void bark() {
System.out.println(“Barking”);
}
}
class SingleInheritance {
public static void main(String args[]) {
Dog d=new Dog ();
d.bark();
d.eat();
}
}
Output-
Barking
Eating
Class A
Class B
Class C
Multilevel Inheritance
Example-
class Animal {
void eat() {
System.out.println(“Eating”);
}
}
class Dog extends Animal {
void bark() {
System.out.println(“Barking”);
}
}
class BabyDog extends Dog {
void cry() {
System.out.println(“Crying”);
}
}
class MultiLevelInheritance {
public static void main(String args[]) {
BabyDog d=new BabyDog ();
d.cry();
d.bark();
d.eat();
}
}
Output-
Crying
Barking
Eating
Hierarchical Inheritance- When two or more classes inherits a single class, it is known as hierarchical inheritance.
Class A
Class B Class C
Hierarchical Inheritance
Example-
class Animal {
void eat() {
System.out.println(“Eating”);
}
}
class Dog extends Animal {
void bark() {
System.out.println(“Barking”);
}
}
class Lion extends Animal {
void roar() {
System.out.println(“Roaring”);
}
}
class HierarchicalInheritance {
public static void main(String args[]) {
Lion c=new Lion ();
c.roar();
c.eat();
}
}
Output-
Roaring
Eating
super keyword-
super keyword is a reserved keyword in Java which is used to refer ParentClass or SuperClass objects.
It is used just like the this keyword. The only difference is that this keyword is used for current object reference
and super keyword is used for super class object reference.
super keyword is also used to access ParentClass or SuperClass Data Members and Methods.
1. Parent Class Instance Methods (By using super keyword)
2. Parent Class Instance Variables (By using super keyword)
3. Parent Class Constructors (By using super() keyword)
Example-
class SuperClass {
int a=10;
void parentClassMethod() {
System.out.println(“Inside Parent Class Method”);
}
}
class ChildClass extends SuperClass {
void childClassMethod() {
System.out.println(“Inside Child Class Method”);
}
void displayMethod() {
System.out.println(super.a);
super.parentClassMethod();
this.childClassMethod();
}
public static void main(String args[]) {
ChildClass obj=new ChildClass();
obj.displayMethod();
}
}
Output-
10
Inside Parent Class Method
Inside Child Class Method
Example of Constructors-
class ParentClass {
int a=10;
void parentClassMethod() {
System.out.println(“Inside Parent Class Method”);
}
ParentClass(){
System.out.println(“Inside Parent Class Constructor”);
}
}
class PracticeClass extends ParentClass {
PracticeClass(){
super(); //Java Compiler runs it implicitly because first statement should be this only
super.parentClassMethod();
}
public static void main(String args[]){
PracticeClass obj= new PracticeClass();
}
}
Example-
class Test {
Test(){
System.out.println(“First Constructor”);
}
Test (int a) {
this(); **
System.out.println(“Second Constructor”);
}
public static void main (String[ ] args) {
Test obj = new Test (10);
}
}
Output-
First Constructor
Second Constructor
**Note- Whenever we define or write constructor the first line is always the calling of the constructor. If we don’t
write it the compiler automatically writes that.
Example-
class ParentClass {
ParentClass() {
System.out.println(“Parent Class Constructor”);
}
}
class ChildClass extends ParentClass {
ChildClass() {
super ();
System.out.println(“Child Class Constructor”);
}
public static void main (String[ ] args){
ChildClass obj=new ChildClass ();
}
}
Output-
ParentClass Constructor
ChildClass Constructor
Method Overriding
If the child class implements the same method present in the parent class again. It is known as Method
Overriding. It helps us to classify a behavior that is specific to the child class.
The subclass can override the method or the parent class only when the method is not declared as final.
Example-
class A {
public void meth1(){
System.out.println(“I am method 1 of class A”);
}
}
class B extends A {
public void meth1(){
System.out.println(“I am method 1 of class B”);
}
}
public class Overriding {
public static void main (String[] args) {
A a=new A();
a.meth1();
B b=new B();
b.meth1();
}
}
final keyword
A variable can be declared as final. Doing so prevents its content from being modified. This means that you must
initialize a final variable when it is declared. Variables declared as final do not occupy memory on a pre-instance
basis. Thus, the final variable is a constant.
Example-
final int FILE_NEW =1;
final int FILE_OPEN =2;
Abstract Class
The abstract class in Java cannot be instantiated (we cannot create objects of abstract classes). We use the abstract
keyword to declare an abstract class. For example,
abstract class Language {
//fields and methods
}
An abstract class can have both the regular methods and abstract methods.
For Example,
abstract class Language {
abstract void method1();
void method2() {
System.out.println(“This is Regular Method”);
}
}
A method that doesn't have its body is known as an abstract method. We use the same abstract keyword to
create abstract methods.
For example,
abstract void display();
If a class contains an abstract method, then the class should be declared abstract. Otherwise, it will generate an
error.
For Example,
//error Class should be abstract
class Language {
abstract void method1();
}
Though abstract classes cannot be instantiated, we can create subclasses from it. We can then access members
of the abstract class using the object of the subclass.
For Example,
abstract class Language {
public void display() {
System.out.println("This is Java Programming");
}
}
class Main extends Language {
public static void main(String[] args) {
Main obj = new Main();
obj.display();
}
}
If the abstract class includes any abstract method, then all the child classes inherited from the abstract superclass
must provide the implementation of the abstract method.
For example,
abstract class Animal {
abstract void makeSound();
public void eat() {
System.out.println("I can eat.");
}
}
class Dog extends Animal {
public void makeSound() {
System.out.println("Bark bark");
}
}
class Main {
public static void main(String[] args) {
Dog d1 = new Dog();
d1.makeSound();
d1.eat();
}
}
Java Abstraction
The major use of abstract classes and methods is to achieve abstraction in Java.
Abstraction is an important concept of object-oriented programming that allows us to hide unnecessary details
and only show the needed information.
This allows us to manage complexity by omitting or hiding details with a simpler, higher-level idea.
For Example-
abstract class MotorBike {
abstract void brake();
}
class SportsBike extends MotorBike {
public void brake() {
System.out.println("SportsBike Brake");
}
}
class MountainBike extends MotorBike {
public void brake() {
System.out.println("MountainBike Brake");
}
}
class Main {
public static void main(String[] args) {
MountainBike m1 = new MountainBike();
m1.brake();
SportsBike s1 = new SportsBike();
s1.brake();
}
}
Interface
An interface is a fully abstract class. It includes a group of abstract methods (methods without a body).
For example,
interface Language {
public void getType();
public voif getVersion();
}
Note- In the above example, all the methods are abstract.
Implementing an Interface
To use an interface, other classes must implement it. We use the implements keyword to implement an interface.
interface Polygon {
void getArea(int length, int breadth);
}
class Rectangle implements Polygon {
public void getArea(int length, int breadth) {
System.out.println("The area of the rectangle is " + (length * breadth));
}
}
class Main {
public static void main(String[] args) {
Rectangle r1 = new Rectangle();
r1.getArea(5, 6);
}
}
Extending an Interface
Similar to classes, interfaces can extend other interfaces. The extends keyword is used for extending interfaces.
For example,
interface Line{
//members of Line Interface
}
interface Polygon extends Line{
//members of Polygon Interface
//members of Line Interface
}
Extending Multiple Interfaces
An interface can extend multiple interfaces. For example,
interface A {
...
}
interface B{
...
}
interface C extends A, B{
....
}
Advantages-
Interfaces provide specifications that a class (which implements it) must follow.
Abstract class and interface both are used to achieve abstraction where we can declare the abstract methods.
Abstract class and interface both can't be instantiated.
Example-
class Error
{
public static void main(String[] args) {
System.out.println(“Hello World”)
}
}
Error- Missing Semi-Colon
Most of the compile time errors are due to typing mistakes. The most common problems are-
Missing Semicolons
Missing brackets in classes and methods
Misspelling of identifiers and keywords
Missing double quotes in strings
Use of undeclared variables
Incompatible types in assignments/ initialization
Bad reference to objects
Use of = in place of == operator
Run-Time Errors- Sometimes a program may compile successfully but may not run properly. Such programs may
produce wrong results due to wrong logic or may terminate due to errors such as Stack Overflow. Most common
run-time errors are-
Dividing an integer by zero
Accessing an element that is out of the bounds of an array
Trying to store a value into an array of an incompatible class or type
Trying to cast an instance of a class to one of its subclasses
Passing a parameter that is not in a valid range or value for a method
Trying to illegally change the state of a thread
Example-
class Error1{
public static void main (String[] args){
int a=10;
int b=5;
int c=5;
int x=a/(b-c);
System.out.println(“x=”+x);
int y=a/(b+c);
System.out.println(“y=”+y);
}
}
Error- Division by Zero
The purpose of Exception Handling Mechanism is to provide a means to detect and report an exceptional
circumstance so that appropriate action can be taken. The mechanism suggests incorporation of a separate error
handling code that performs the following task-
1. Find the exception (hit the exception)
2. Inform the error (throw the exception)
3. Receive the error (catch the exception)
4. Take action (Handles the exception)
Types of Exception
Exception in Java can be categorized into two types-
Checked Exception- These exceptions are handled in the code itself with the help of try-catch blocks. Checked
Exceptions are extended from java.lang.Exception class.
Unchecked Exception- These exceptions are not essentially handled in the program code instead the JVM handles
such exceptions. They are extended from java.lang.RuntimeException class.
Syntax-
Java uses a keyword called try to preface a block of code that might contain some error. 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.
try {
statements; //Generates an exception
}
catch (Exception-type e) {
statements; // Processes the Exception
}
Example-
class demo{
public static void main(String [] args){
int a=10,b=5,c=5,x,y;
try {
x=a/(b-c);
}
catch(ArithmeticException e){
System.out.println(“Divide by Zero”);
}
y=a/(b+c);
System.out.println(“y=”+y);
}
}
Finally Statement-
Java supports another statement known as finally statement that can be used to handle an exception that is not
caught by any previous catch statements. Finally bock can be used to handle any exception generated within a try
block. It may be added immediately after try block or after the last catch block shown as follows-
1. try {
statements;
}
finally {
statements;
}
2. try {
statements;
}
catch (Exception-Type-1 e) {
statements;
}
catch (Exception-Type-2 e) {
statements;
}
.
.
.
finally {
statements;
}
Nested try statements-
class nested{
public static void main (String [] args){
int [] marks=new int [3];
marks [0]=7;
marks [1]=56;
marks [2]=6;
try {
System.out.println(“Welcome”);
try {
System.out.println(marks[9]);
}
catch (ArrayIndexOutOfBoundException e){
System.out.println(“Sorry this index doesn’t exist”);
System.out.println(“Exception in Level 2”);
}
}
catch(Exception e){
System.out.println(“Exception in Level 1”);
}
}
}
Syntax-
public class MyException extends Exception {
//variables & methods
}
Throwing our own Exceptions-
The Java throw keyword is used to throw an exception explicitly. There may be times when we would like to throw
our own exceptions. We can do this by using keyword throw as show below-
throw new Throwable subclass;
Example-
throw new ArithmeticException();
throws keyword-
It is used to declare an exception. It gives an information to the programmer that there may occur an exception. So,
it is better for the programmer to provide the exception handling code so that the normal flow of the program can
be maintained.
Syntax-
return_type_method_name() throws exception_class{
//method code
}
throw vs throws-
Multithreading
Modern Operating System has the capability to execute several programs simultaneously i.e., at the same time. This
ability is known as Multitasking. In system’s terminology it is called as Multithreading.
Multithreading is a conceptual programming where a program is divide into two or more subprograms which can be
implemented at the same time in parallel.
In most of our computer there is only one processor and hence 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 human being that all of them
are being done simultaneously.
Thread- A thread is similar to a program that has a single flow of control. It has a beginning, a body and an end. The
entire program which we have done till now are called single thread program as they have single flow of execution.
Java has a unique property that it supports multithreading. That is Java enables us to use multiple flows of control in
developing program and each flow of control is considered as a separate program known as thread.
A program that contains multiple flows of control is known as multithreaded program.
Main
Method
Module
start start
start
switching switching
Thread A Thread B Thread C
A Multithreaded Program
Multithreading Multitasking
It is a programming concept. It is an operating system control.
It supports execution of multiple parts of the same It supports execution of multiple programs
program simultaneously. simultaneously.
The processor switches between different parts/ threads The processor switches between multiple programs.
of the program.
It is highly efficient. It is less efficient as compared to multithreading.
It helps in developing efficient programs. It helps in developing efficient Operating System.
Creating Threads- Threads are implemented in the form of objects that contain run() method. The run() method is
the heart and soul of any thread. It makes the entire body of the thread.
Syntax- public void run () {
........
}
This run() is invoked by calling the start() method. Now remember this that if you want this run() method to behave
like a Threaded program you need to call the start() method. If you call it by its name i.e., run() it is not going to show
any multithreading property.
Extending the Thread Class- We can make our class runnable as thread by extending the class java.lang.Thread. This
gives access to all the thread methods directly. It includes following steps-
Declare the class as extending the Thread class
Implement the run() method that is responsible for executing the sequence of code that the thread will execute.
Create a thread object and call the start() method to initiate the thread execution.
Syntax-
class MyThread extends Thread {
public void run() {
//Thread Code Here
}
MyThread aThread= new MyThread();
aThread.start(); //invokes run() method
}
Example-
class A extends Thread{
public void run(){
for(int i=1;i<5;i++){
System.out.println(“i” +i);
}
}
}
class B extends Thread{
public void run(){
for(int j=1;j<5;j++){
System.out.println(“j” +j);
}
}
}
class ThreadTest{
public static void main(String[] args){
new A().start(); //Creates the Temporary Object
new B().start();
}
}
Stopping a Thread- Whenever we want to stop a thread from running further, we may do so by calling its stop()
method.
Syntax- aThread.stop();
This statement causes a 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 methods:
sleep() //blocked for a specified time
suspend() //blocked until further orders
wait() //block until certain conditions occurs
These methods cause the thread to go into the blocked state. The thread will return to the runnable state
when the specified time is over in the case of sleep().
The resume() method is invoked in the case of suspend().
The notify() method is called in the case of wait().
Life Cycle of a Thread-
During a lifetime of a thread, there are many states it can enter. They include-
1. Newborn State
2. Runnable State
3. Running State
4. Blocked State
5. Dead State
New
stop()
start()
Runnable stop()
Dead
run() yield()
Running End of
Execution
resume()
notify() suspend() sleep()
wait() stop()
Blocked
Newborn State-
When a thread object is created, the thread is said to be in born state. At this moment, the thread is not scheduled
for running. At this state, the following may be done.
Newborn
start stop
Runnable Dead
State State
Runnable State-
The runnable state means that the thread is ready for execution and is waiting for the availability of the processor. In
simple terms, the thread is ready but not got the processor time. If all the threads have equal priority then all follow
a queue system and the processor gives time to each thread in round robin fashion.
yield
suspend()
resume()
It has been made to sleep using sleep() method for some specified time . After the given time the thread itself
join the Runnable State.
sleep(t)
after(t)
It has been told to wait until some event occurs. This is done using wait() method and it scheduled to run again
by notify() method.
wait()
notify()
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 the thread is suspended, sleeping or waiting in order to satisfy certain
requirements.
Dead State-
A thread is said to be in the dead state when it has been killed by using kill() method or it has successfully completed
its execution.
Example-
class A extends Thread {
public void run(){
for(int i=1; i<=5;i++) {
if(i==1)
yield();
System.out.println("\n From Thread A: i=" +i);
}
System.out.println("End of Thread A");
}
}
class B extends Thread {
public void run(){
for(int j=1;j<=5;j++) {
System.out.println("\n From Thread B: j=" +j);
if(j==3)
stop();
}
System.out.println("End of Thread B");
}
}
class ThreadMethods{
public static void main(String[] args){
A threadA= new A();
B threadB= new B();
System.out.println("\n Start thread A");
threadA.start();
System.out.println("\n Start thread B");
threadB.start();
}
}
Output-
Start Thread A
Start Thread B
From Thread B : j=1
From Thread B : j=2
From Thread A : i=1
From Thread A : i=2
From Thread B : j=3
From Thread A : i=3
From Thread A : i=4
From Thread A : i=5
Exit from A
Thread Priority-
In Java every Thread is assigned a priority and based on this priority the threads are executed. Usually all the threads
have equal priority and hence they share the processor on a first come first serve basis.
Java provides us the following methods related to Thread Priority-
setPriority()
getPriority()
getId()
currentThread()
setPriority()- Java permits us to set priority of a thread using the setPriority() method.
Syntax-
ThreadName.setPriority(int Number)
Here, intNumber is an integer value to which the thread’s priority is set. The Thread Class provides us many thread
priority constants-
MIN_PRIORITY= 1
NORM_PRIORITY= 5
MAX_PRIORITY= 10
getId()- Where thread has its unique id and if we want to check and get that ID we use this method.
Syntax-
ThreadName.getId()
Example-
class A extends Thread {
public void run(){
System.out.println("This is Thread A\t Thread ID:" +Thread.currentThread().getId()+"\t Thread
Priority:"+Thread.currentThread().getPriority());
}
}
class B extends Thread {
public void run(){
System.out.println("This is Thread B\t Thread ID:" +Thread.currentThread().getId()+"\t Thread
Priority:"+Thread.currentThread().getPriority());P
}
}
class ThreadPriority{
public static void main(String[] args){
A threadA= new A();
B threadB= new B();
threadA.setPriority(Thread.MIN_PRIORITY);
threadB.setPriority(Thread.NORM_PRIORITY);
System.out.println("This is Main Thread A\t Thread ID:" +Thread.currentThread().getId()+"\t Thread
Priority:"+Thread.currentThread().getPriority());
threadA.start();
threadB.start();
}
}
Output-
This is Main Thread A Thread ID:1 Thread Priority:5
This is Thread B Thread ID:11 Thread Priority:5
This is Thread A Thread ID:10 Thread Priority:1
Synchronization-
We know that threads uses their own data and methods provided inside their run() method. Consider a case when
try to use data and methods outside themselves. In such situation they may compete for the same resource and may
lead to serious problems. For an instance suppose there are two threads, one wants to read the data from the
resource and second wants to read the data at the same time. In such situation, result will be unexpected. Java
enables us to overcome this situation using a technique called Synchronization.
The keyword synchronized helps to solve such problems by keeping a watch on such locations. When we create a
method as synchronized, Java creates monitor and hands it over to the thread that calls the method first time. As
long as the thread holds the monitor, no other thread can enter the synchronized section of code.
Syntax-
synchronized void update() {
//code here is synchronized
}
Whenever a thread has completed its work of using synchronized method, it will hand over the monitor to the next
thread that is ready to use the same resource.
Example-
class Printing{
synchronized void print(char ch){
for(i=1;i<=5;i++){
for(j=1;j<=i;j++){
System.out.print(ch);
}
System.out.println();
}
}
}
class A extends Thread{
printing p;
A(printing p){
this.p=p;
}
public void run(){
p.print("*");
}
}
class B extends Thread{
printing p;
B(printing p){
this.p=p;
}
public void run(){
p.print("#");
}
}
class Synchronization{
public static void main(String[] args){
printing aa=new printing();
A threadA=new A(aa);
B threadB=new B(aa);
threadA.start();
threadB.start();
}
}
Output-
*
**
***
****
*****
#
##
###
####
#####
Example-
class X implements Runnable{
public void run(){
for(int i=1;i<=10;i++){
System.out.println("\t Thread X" +i);
}
System.out.println("End of Thread X");
}
}
class Runnable{
public static void main(String[] args){
X runnable=new X();
Thread threadX=new Thread(runnable);
threadX.start();
}
}
Output-
ThreadX : 1
ThreadX : 2
ThreadX : 3
ThreadX : 4
ThreadX : 5
ThreadX : 6
ThreadX : 7
ThreadX : 8
ThreadX : 9
ThreadX : 10
End of ThreadX
Inter-Thread Communication-
Inter-Thread Communication can be defined as the exchange of messages between two or more threads. The
transfer of messages takes place before or after the change of state of a thread. Java implements inter-thread
communication with the help of following three methods-
1. notify()- Resumes the first thread that went into the sleep mode. The object class declaration of this method is-
final void notify()
2. notifyall()- Resumes all the threads that are in sleep mode. The execution of these threads happens as per
priority. The object class declaration of this method is-
final void notifyall()
3. wait()- Sends the calling thread into the sleep mode. The desired waiting time period is specified as an argument
to the wait() method. The object class declaration of this method is-
final void wait()