Java Unit 3
Java Unit 3
****************************************************************
1. Single Inheritance
In single inheritance, a sub-class is derived from only one super class. It inherits
the properties and behavior of a single-parent class. Sometimes, it is also
known as simple inheritance.
//Super class
class Vehicle {
Vehicle() {
System.out.println("This is a Vehicle");
}
}
// Subclass
class Car extends Vehicle {
Car() {
System.out.println("This Vehicle is Car");
}
}
public class Test {
public static void main(String[] args) {
// Creating object of subclass invokes base class constructor
Car obj = new Car();
}
}
Output
This is a Vehicle
This Vehicle is Car
***************************************************************
2. Multilevel Inheritance
In Multilevel Inheritance, a derived class will be inheriting a base class and as
well as the derived class also acts as the base class for other classes.
class Vehicle {
Vehicle() {
System.out.println("This is a Vehicle");
}
}
class FourWheeler extends Vehicle {
FourWheeler() {
System.out.println("4 Wheeler Vehicles");
}
}
class Car extends FourWheeler {
Car() {
System.out.println("This 4 Wheeler Vehicle is a Car");
}
}
public class Geeks {
public static void main(String[] args) {
Car obj = new Car(); // Triggers all constructors in order
}
}
Output
This is a Vehicle
4 Wheeler Vehicles
This 4 Wheeler Vehicle is a Car
****************************************************************
3. Hierarchical Inheritance
In hierarchical inheritance, more than one subclass is inherited from a single
base class. i.e. more than one derived class is created from a single base class.
For example, cars and buses both are vehicle
class Vehicle {
Vehicle() {
System.out.println("This is a Vehicle");
}
}
class Car extends Vehicle {
Car() {
System.out.println("This Vehicle is Car");
}
}
class Bus extends Vehicle {
Bus() {
System.out.println("This Vehicle is Bus");
}
}
public class Test {
public static void main(String[] args) {
Car obj1 = new Car();
Bus obj2 = new Bus();
}
}
Output
This is a Vehicle
This Vehicle is Car
This is a Vehicle
This Vehicle is Bus
****************************************************************
**********
4. Multiple Inheritance (Through Interfaces)
An Interface in Java programming language is defined as an abstract type used
to specify the behaviour of a class. An interface in Java is a blueprint of a
behaviour. A Java interface contains static constants and abstract methods.
Key Properties of Interface:
The interface in Java is a mechanism to achieve abstraction.
By default, variables in an interface are public, static and final.
It is used to achieve abstraction and multiple inheritance in Java.
It supports loose coupling (classes depend on behavior, not implementation).
In other words, interfaces primarily define methods that other classes must
implement.
An interface in Java defines a set of behaviours that a class can implement,
usually representing a CAN-DO relationship, but not always in every scenario.
Example: This example demonstrates how an interface in Java defines
constants and abstract methods, which are implemented by a class.
import java.io.*;
// Interface Declared
interface testInterface {
class Main
{
public static void main(String[] args)
{
TestClass t = new TestClass();
t.display();
System.out.println(t.a);
}
}
Output
Hello
10
Note: In Java, the abstract keyword applies only to classes and methods,
indicating that they cannot be instantiated directly and must be implemented.
When we decide on a type of entity by its behaviour and not via attribute we
should define it as an interface.
Syntax:
interface InterfaceName {
// Constant fields (public static final by default)
int CONSTANT = 10;
// Abstract method (public abstract by default)
void methodName();
// Default method (JDK 8+)
default void defaultMethod() {
System.out.println("Default implementation");
}
// Static method (JDK 8+)
static void staticMethod() {
System.out.println("Static method in interface");
}
// Private method (JDK 9+)
private void privateMethod() {
System.out.println("Private helper method");
}
}
Note:
Private methods can only be called inside default or static methods in
the interface, not by implementing classes
Static methods are also accessible via the3interface itself not through
objects
To declare an interface, use the interface keyword. It is used to provide total
abstraction. That means all the methods in an interface are declared with an
empty body and are public and all fields are public, static and final by default. A
class that implements an interface must implement all the methods declared in
the interface. To implement the interface, use the implements keyword.
interface Vehicle {
// Change gear
@Override
public void changeGear(int newGear){
gear = newGear;
}
// Increase speed
@Override
public void speedUp(int increment){
speed = speed + increment;
}
// Decrease speed
@Override
public void applyBrakes(int decrement){
speed = speed - decrement;
}
int speed;
int gear;
// Change gear
@Override
public void changeGear(int newGear){
gear = newGear;
}
// Increase speed
@Override
public void speedUp(int increment){
speed = speed + increment;
}
// Decrease speed
@Override
public void applyBrakes(int decrement){
speed = speed - decrement;
}
public void printStates() {
System.out.println("speed: " + speed
+ " gear: " + gear);
}
class Main
{
public static void main (String[] args)
{
// Instance of Bicycle(Object)
Bicycle bicycle = new Bicycle();
bicycle.changeGear(2);
bicycle.speedUp(3);
bicycle.applyBrakes(1);
}
}
Output
Addition : 3
Substraction : 1
Example:
interface LandVehicle {
default void landInfo() {
System.out.println("This is a LandVehicle");
}
}
interface WaterVehicle {
default void waterInfo() {
System.out.println("This is a WaterVehicle");
}
}
// Subclass implementing both interfaces
class AmphibiousVehicle implements LandVehicle, WaterVehicle {
AmphibiousVehicle() {
System.out.println("This is an AmphibiousVehicle");
}
}
public class Test {
public static void main(String[] args) {
AmphibiousVehicle obj = new AmphibiousVehicle();
obj.waterInfo();
obj.landInfo();
}
}
Output
This is an AmphibiousVehicle
This is a WaterVehicle
This is a LandVehicle
5. Hybrid Inheritance
It is a mix of two or more of the above types of inheritance. In Java, we can
achieve hybrid inheritance only through Interfaces if we want to involve
multiple inheritance to implement Hybrid inheritance.
Explanation:
class Car extends Vehicle->Single Inheritance
class Bus extends Vehicle and class Bus extends Fare->Hybrid Inheritance
(since Bus inherits from two sources, forming a combination of single +
multiple inheritance).
Advantages of Inheritance in Java
Code Reusability: Inheritance allows for code reuse and reduces the
amount of code that needs to be written. The subclass can reuse the
properties and methods of the superclass, reducing duplication of code.
Abstraction: Inheritance allows for the creation of abstract classes that
define a common interface for a group of related classes. This promotes
abstraction and encapsulation, making the code easier to maintain and
extend.
Class Hierarchy: Inheritance allows for the creation of a class hierarchy,
which can be used to model real-world objects and their relationships.
Polymorphism: Inheritance allows for polymorphism, which is the ability
of an object to take on multiple forms. Subclasses can override the
methods of the superclass, which allows them to change their behavior
in different ways.
Disadvantages of Inheritance in Java
Complexity: Inheritance can make the code more complex and harder to
understand. This is especially true if the inheritance hierarchy is deep or
if multiple inheritances is used.
Tight Coupling: Inheritance creates a tight coupling between the
superclass and subclass, making it difficult to make changes to the
superclass without affecting the subclass.
Important Read it : The point Constructor is missing in 2nd chapter so I just put
here the notes about constructors.Is to be covered as follows:
Java Constructors
In Java, constructors play an important role in object creation. A constructor is
a special block of code that is called when an object is created. Its main job is
to initialize the object, to set up its internal state, or to assign default values to
its attributes. This process happens automatically when we use the "new"
keyword to create an object.
Characteristics of Constructors:
Same Name as the Class: A constructor has the same name as the class
in which it is defined.
No Return Type: Constructors do not have any return type, not even
void. The main purpose of a constructor is to initialize the object, not to
return a value.
Automatically Called on Object Creation: When an object of a class is
created, the constructor is called automatically to initialize the object’s
attributes.
Used to Set Initial Values for Object Attributes: Constructors are
primarily used to set the initial state or values of an object’s attributes
when it is created.
Now, let us look at a simple example to understand how a constructor works in
Java.
Example: This program demonstrates how a constructor is automatically
called when an object is created in Java.
// Java Program to demonstrate
// Constructor usage
import java.io.*;
// Driver Class
class Drive {
// Constructor
Drive()
{
super();
System.out.println("Constructor Called");
}
// main function
public static void main(String[] args)
{
Drive d1 = new Drive();
}
}
Output
Constructor Called
Note: It is not necessary to write a constructor for a class. It is because the Java
compiler creates a default constructor (constructor with no arguments) if your
class doesn't have any.
Why Do We Need Constructors in Java
Constructors play a very important role, it ensures that an object is properly
initialized before use.
What happens when we don't use constructors:
Without constructors:
Objects might have undefined or default values.
Extra initialization methods would be required.
Risk of improper object state
Think of a Box. If we talk about a box class then it will have some class variables
(say length, breadth, and height). But when it comes to creating its object (i.e
Box will now exist in the computer's memory), then can a box be there with no
value defined for its dimensions? The answer is No.
So, constructors are used to assign values to the class variables at the time of
object creation, either explicitly done by the programmer or by Java itself
(default constructor).
When Java Constructor is Called?
Each time an object is created using a new() keyword, at least one constructor
(it could be the default constructor) is invoked to assign initial values to
the data members of the same class. Rules for writing constructors are as
follows:
The constructor of a class must have the same name as the class name in
which it resides.
A constructor in Java can not be abstract, final, static, or Synchronized.
Access modifiers can be used in constructor declaration to control its
access i.e which other class can call the constructor.
So, we have learned constructors are used to initialize the object's state.
Like methods , a constructor also contains a collection of statements (i.e.
instructions) that are executed at the time of object creation.
Types of Constructors in Java
Now is the correct time to discuss the types of the constructor, so primarily
there are three types of constructors in Java are mentioned below:
Default Constructor
Parameterized Constructor
Copy Constructor
1. Default Constructor in Java
A constructor that has no parameters is known as default constructor. A
default constructor is invisible. And if we write a constructor with no
arguments, the compiler does not create a default constructor. Once you
define a constructor (with or without parameters), the compiler no longer
provides the default constructor. Defining a parameterized constructor does
not automatically create a no-argument constructor, we must explicitly define
if needed. The default constructor can be implicit or explicit.
Implicit Default Constructor: If no constructor is defined in a class, the
Java compiler automatically provides a default constructor. This
constructor doesn’t take any parameters and initializes the object with
default values, such as 0 for numbers, null for objects.
Explicit Default Constructor: If we define a constructor that takes no
parameters, it's called an explicit default constructor. This constructor
replaces the one the compiler would normally create
automatically. Once you define any constructor (with or without
parameters), the compiler no longer provides the default constructor for
you.
Example: This program demonstrates the use of a default constructor, which is
automatically called when an object is created.
// Java Program to demonstrate
// Default Constructor
import java.io.*;
// Driver class
class Stud{
// Default Constructor
Stud() {
System.out.println("Default constructor");
}
// Driver function
public static void main(String[] args)
{
Stud hello = new Stud();
}
}
Output
Default constructor
Note: Default constructor provides the default values to the object like 0, null,
false etc. depending on the type.
// Copy Constructor
Emp(Emp obj2)
{
this.name = obj2.name;
this.id = obj2.id;
}
}
class Main {
public static void main(String[] args)
{
// This would invoke the parameterized constructor
System.out.println("First Object");
Emp e1 = new Emp("Shweta", 68);
System.out.println("EmpName: " + e1.name
+ " and EmpId: " + e1.id);
System.out.println();
// This would invoke the copy constructor
Emp e2 = new Emp(e1);
System.out.println(
"Copy Constructor used Second Object");
System.out.println("EmpName: " + e2.name
+ " and EmpId: " + e2.id);
}
}
Output
First Object
EmpName: Shweta and EmpId: 68
Copy Constructor used Second Object
EmpName: Shweta and EmpId: 68
Constructor Overloading
This is a key concept in OOPs related to constructors is constructor overloading.
This allows us to create multiple constructors in the same class with different
parameter lists.
Example: This example, demonstrates constructor overloading, where multiple
constructors perform the same task (initializing an object) with different
types or numbers of arguments.
// Java Program to illustrate constructor overloading
// using same task (addition operation ) for different
// types of arguments
import java.io.*;
class Emp {
// constructor with one argument
Emp(String name)
{
System.out.println("Constructor with one "
+ "argument - String: " + name);
}
// constructor with two arguments
Emp(String name, int age)
{
System.out.println(
"Constructor with two arguments: "
+ " String and Integer: " + name + " " + age);
}
// Constructor with one argument but with different
// type than previous
Emp(long id)
{
System.out.println(
"Constructor with one argument: "
+ "Long: " + id);
}
}
class Main {
public static void main(String[] args)
{
// Creating the objects of the class named ‘Emp’
// by passing different arguments
// Invoke the constructor with one argument of
// type 'String'.
Emp e2 = new Emp("Shweta");
// Invoke the constructor with two arguments
Emp e3 = new Emp("Amiya", 28);
Method Overloading
As we discussed above, Method overloading in Java means when there are
multiple functions with the same name but different parameters then these
functions are said to be overloaded. Functions can be overloaded by changes in
the number of arguments or/and a change in the type of arguments.
Example: Method overloading by changing the number of arguments
// Method overloading By using
// Different Types of Arguments
// Class 1
// Helper class
class Helper {
// Method with 2 integer parameters
static int Multiply(int a, int b)
{
// Returns product of integer numbers
return a * b;
}
// Method 2
// With same name but with 2 double parameters
static double Multiply(double a, double b)
{
// Returns product of double numbers
return a * b;
}
}
// Class 2
// Main class
class Main
{
// Main driver method
public static void main(String[] args) {
// Calling method by passing
// input as in arguments
System.out.println(Helper.Multiply(2, 4));
System.out.println(Helper.Multiply(5.5, 6.3));
}
}
Output
8
34.65
Explanation:
The Multiply method is overloaded with different parameter types. The
compiler picks the correct method during compile time based on the
arguments.
2. Runtime Polymorphism
Runtime Polymorphism in Java known as Dynamic Method Dispatch. It is a
process in which a function call to the overridden method is resolved at
Runtime. This type of polymorphism is achieved by Method
Overriding. Method overriding, on the other hand, occurs when a derived class
has a definition for one of the member functions of the base class. That base
function is said to be overridden.
Method Overriding
Method overriding in Java means when a subclass provides a specific
implementation of a method that is already defined in its superclass. The
method in the subclass must have the same name, return type, and parameters
as the method in the superclass. Method overriding allows a subclass to modify
or extend the behavior of an existing method in the parent class. This enables
dynamic method dispatch, where the method that gets executed is determined
at runtime based on the object's actual type.
Example: This program demonstrates method overriding in Java, where the
Print() method is redefined in the subclasses (subclass1 and subclass2) to
provide specific implementations.
// Java Program for Method Overriding
// Class 1
// Helper class
class Parent {
// Class 2
// Helper class
class subclass1 extends Parent {
// Method
void Print() {
System.out.println("subclass1");
}
}
// Class 3
// Helper class
class subclass2 extends Parent {
// Method
void Print() {
System.out.println("subclass2");
}
}
// Class 4
// Main class
class Geeks {
a = new subclass2();
a.Print();
}
}
Output
subclass1
subclass2
Explanation: In the above example, when an object of a child class is created,
then the method inside the child class is called. This is because the method in
the parent class is overridden by the child class. This method has more priority
than the parent method inside the child class. So, the body inside the child
class is executed.
Advantages of Polymorphism
Encourages code reuse.
Simplifies maintenance.
Enables dynamic method dispatch.
Helps in writing generic code that works with many types.
Disadvantages of Polymorphism
It can make more difficult to understand the behavior of an object.
This may cause performance issues, as polymorphic behavior may
require additional computations at runtime.
// final variable
final int b = 6;
Note: If we declare any variable as final, we can't modify its value. Attempting
to do so results in a compile-time error.
In the above example, we used the final keyword to declare a variable that
cannot be modified after its initialization. Similarly, the final keyword can also
be applied to methods and classes in Java to impose certain restrictions.
finally Keyword
The finally keyword in Java is used to create a block of code that always
executes after the try block, regardless of whether an exception occurs or not.
Syntax
try {
// Code that might throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
} finally {
// Code that will always execute
}
Example: The below Java program demonstrates the working of finally block in
exception handling.
public class Geeks {
public static void main(String[] args)
{
try {
System.out.println("Inside try block");
int result
= 10 / 0; // This will cause an exception
}
catch (ArithmeticException e) {
System.out.println("Exception caught: "
+ e.getMessage());
}
finally {
System.out.println(
"finally block always execute");
}
}
}
Output:
System.gc();
Output
Explanation: In the above example, an object "g" is created and its hash code is
printed. The object is made eligible for garbage collection by setting it to null
and invoking System.gc().
final vs finally vs finalize
The table below illustrates the differences between "final", "finally" and
"finalize."
final finally finalize
The finally block in
final keyword applies
exception handling is finalize is a method of
restrictions on variable,
used with try-catch object class
method and classes.
block.
The code that is written
finalize method in Java
Prevent modification of inside finally block is
is used to perform
variables, inheritance of always executed after
cleanup operations
classes or overriding of the try-catch block
before an object is
methods. whether an exception
garbage collected.
occurs or not .
Objects, specifically by
Variables, methods and Only within a try-catch
overriding the method
classes. block.
in a class
Called by the garbage
collector when an
Executes when Always executed after
object is about to be
declared. try-catch block.
deleted, but it's not
guaranteed to run.
Modifier Description
Default declarations are visible only within the package (package private)
Private declarations are visible within the class only
Protected declarations are visible within the package or all subclasses
Public declarations are visible everywhere
class Data {
// private variable
private String name;
}
public class Main {
public static void main(String[] main){
class Animal {
// protected method
protected void display() {
System.out.println("I am an animal");
}
}
// Animal.java file
// public class
class Animal {
// public variable
public int legCount;
// public method
public void display() {
System.out.println("I am an animal.");
System.out.println("I have " + legCount + " legs.");
}
}
// Main.java
public class Main {
public static void main( String[] args ) {
// accessing the public class
Animal animal = new Animal();
Java Packages
Packages in Java are a mechanism that encapsulates a group of classes, sub-
packages and interfaces. Packages are used for:
Prevent naming conflicts by allowing classes with the same name to exist
in different packages, like college.staff.cse.Employee and
college.staff.ee.Employee.
Make it easier to organize, locate and use classes, interfaces and other
components.
Provide controlled access for Protected members that are accessible
within the same package and by subclasses. Default members (no access
specifier) are accessible only within the same package.
By grouping related classes into packages, Java promotes data encapsulation,
making code reusable and easier to manage. Simply import the desired class
from a package to use it in your program.
Creating Custom Packages
Step 1: Create a directory in which we create our packages and Java files.
mkdir PROGRAMMING
Step 2: Now, change the directory and create another folder inside the main
folder
cd PROGRAMMING
mkdir JavaProgramming
cd JavaProgramming
mkdir arrays
Step 3: Now create an empty text file and write the below Java code and don't
forget to save it with the same name as the class with .java extension
(TwoPointers.java)
TwoPointers Class.
package JavaProgramming.arrays;
Folder Structure
Working of Java Packages
Directory Structure: Package names and directory structures are closely
related. For example, if a package name is college.staff.cse, then three
directories are, college, staff and cse, where cse is inside staff and staff is inside
the college.
Naming Conventions: Package names are written in reverse order of domain
names, e.g., org.geeksforgeeks.practice. In a college, the convention might be:
college.tech.cse
college.tech.ee
college.art.history
Example:
import java.util.*;
Here, util is a sub-package created inside the java package.
Accessing Classes Inside a Package
In Java, we can import classes from a package using either of the
following methods:
1. Import a specific class:
import java.util.Vector;
This imports only the Vector class from the java.util package.
2. Import all classes from a package:
import java.util.*;
This imports all classes and interfaces from the java.util package but does not
include sub-packages.
Example: Import the Vector class
import java.util.Vector;
public Geeks() {
System.out.println(l);
}
new Geeks();
}
}
Output
[3, 5, 7]
Note:
Using import package.*; imports all classes in a package, but not classes
from its sub-packages.
When two packages have classes with the same name (e.g.,
java.util.Date and my.package.Date), use the fully qualified name to
avoid conflicts:
import java.util.Date;
import my.package.Date;
Types of Java Packages
Built-in Packages
User-defined Packages
1. Built-in Packages
These packages consist of a large number of classes which are a part of
Java API.Some of the commonly used built-in packages are:
java.lang: Contains language support classes(e.g classes which defines
primitive data types, math operations). This package is automatically
imported.
java.io: Contains classes for supporting input / output operations.
java.util: Contains utility classes which implement data structures like
Linked List, Dictionary and support ; for Date / Time operations.
java.applet: Contains classes for creating Applets.
java.awt: Contain classes for implementing the components for graphical
user interfaces (like button , ;menus etc). 6)
java.net: Contain classes for supporting networking operations.
2. User-defined Packages
These are the packages that are defined by the user.
1. Create the Package:
First we create a directory myPackage (name should be same as the name of
the package). Then create the MyClass inside the directory with the first
statement being the package names.
Example:
package myPackage;
o.getNames(s);
}
}
class Main {
public static void main(String args[]) {
Output
Hello
Handling Name Conflicts
When two packages contain a class with the same name (e.g., java.util.Date
and java.sql.Date), specify the full package name to avoid conflicts.
import java.util.*;
import java.sql.*;
//And then use Date class, then we will get a compile-time error :
Date today ; //ERROR-- java.util.Date or java.sql.Date?
The compiler will not be able to figure out which Date class do we want. This
problem can be solved by using a specific import statement:
import java.util.Date;
import java.sql.*;
If we need both Date classes then, we need to use a full package name every
time we declare a new object of that class. For Example:
java.util.Date deadLine = new java.util.Date();
java.sql.Date today = new java.sql.Date();
Directory Structure and CLASSPATH
Package names correspond to a directory structure. For example, a class Circle
in package com.zzz.project1.subproject2 is stored as:
$BASE_DIR/com/zzz/project1/subproject2/Circle.class
.c:\javaproject\classes;d:\tomcat\lib\servlet-api.jar
The dot (.) represents the current working directory.
To check the current setting of the CLASSPATH, issue the following
command:
> SET CLASSPATH
CLASSPATH can be set temporarily for that particular CMD shell session by
issuing the following command:
> SET CLASSPATH=.;c:\javaproject\classes;d:\tomcat\lib\servlet-api.jar
Instead of using the CLASSPATH environment variable, you can also use the
command-line option -classpath or -cp of the javac and java commands, for
example,