Unit – 2
Inheritance in Java: Inheritance is an object-oriented programming concept in which one class
acquires the properties and behaviour of another class. It represents a parent-child relationship between
two classes. This parent-child relationship is also known as an IS-A relationship.
or
Java Inheritance is a fundamental concept in object-oriented programming that allows a new class to inherit
properties and behaviours (fields and methods) from an existing class. This promotes code reusability and
establishes a hierarchical relationship between classes.
Key Concepts:
Superclass (Parent Class): The class whose properties and methods are inherited.
Subclass (Child Class): The class that inherits from the superclass.
Inheritance is used to create a new class that is a type of an existing class. It helps in extending the
functionality of a class without modifying it, thereby adhering to the Open/Closed Principle of software
design.
class Superclass
// fields and methods
class Subclass extends Superclass
// additional fields and methods
Example
class Vehicle {
protected String brand = "Ford"; // Vehicle attribute
public void honk() { // Vehicle method
System.out.println("Tuut, tuut!");
}
class Car extends Vehicle {
private String modelName = "Mustang"; // Car attribute
public static void main(String[] args) {
// Create a myCar object
Car myCar = new Car();
// Call the honk() method (from the Vehicle class) on the myCar object
myCar.honk();
// Display the value of the brand attribute (from the Vehicle class) and the value of the
modelName from the Car class
System.out.println(myCar.brand + " " + myCar.modelName);
The 5 types of inheritance
Single-level inheritance
Multi-level Inheritance
Hierarchical Inheritance
Multiple Inheritance
Hybrid Inheritance
1. Single-level inheritance: Single-level inheritance in Java is a fundamental concept
where a subclass inherits from only one superclass. This means that the subclass can acquire the
properties and methods of the superclass, enabling code reuse and the extension of existing
functionality.
2. Multi-level Inheritance
Multilevel inheritance in Java is a feature that allows a class to inherit properties and behaviours from another
class, which in turn inherits from another class, forming a "chain" of inheritance. This mechanism enables a
class to inherit methods and fields from multiple ancestors but in a direct line, where each class in the chain
inherits from one class directly above it.
3. Hierarchical Inheritance
Hierarchical inheritance in Java occurs when one base class (superclass) is inherited by multiple
subclasses. In this type of inheritance, all the features that are common in child classes are included in the
base class. This way, the code becomes more manageable and reusable.
4. Multiple Inheritance
Multiple inheritance refers to a feature in object-oriented programming where a class can inherit properties
and methods from more than one parent class. This concept allows a subclass to inherit behaviours and
attributes from multiple base (or super) classes, creating a rich, multifaceted hierarchy.
However, it's important to note that Java does not support multiple inheritance for classes directly due
to the complexity and potential for ambiguity but it can be achieved through the concept of Interfaces
in java.
Java provides a mechanism to achieve polymorphism and code reuse through interfaces. An
interface in Java is a reference type, similar to a class, that can contain only constants,
method signatures, default methods, static methods, and nested types. Interfaces cannot
contain instance fields or constructor methods. A class in Java can implement multiple
interfaces, allowing it to inherit abstract methods from multiple sources.
5. Hybrid Inheritance
Hybrid inheritance is a combination of two or more types of inheritance, such as hierarchical, multiple,
multilevel, or single inheritance. It integrates various inheritance mechanisms to achieve a specific
design or functionality. However, it's important to note that due to Java's restriction on extending
multiple classes directly (to avoid complexity and ambiguity issues like the Diamond Problem), hybrid
inheritance in Java is primarily achieved through a mix of class inheritance (using
the extends keyword) and interface implementation (using the implements keyword).
In Java, hybrid inheritance can involve:
Single and Multilevel Inheritance through classes: A class inherits from one superclass, and then another
class inherits from that subclass, forming a linear inheritance chain.
Hierarchical Inheritance through classes: Multiple classes inherit from a single parent class.
Multiple Inheritance through Interfaces: A class implements multiple interfaces, inheriting the abstract
methods from these interfaces.
Combining Class Inheritance and Interface Implementation: A class extends another class and also
implements one or more interfaces.
Method Overriding :
A subclass can implement a parent class method based on its requirement.
In object-oriented terms, overriding means to override the functionality of an existing method.
Method overriding allows us to achieve run-time polymorphism and is used for writing specific definitions of a
subclass method that is already defined in the superclass.
The method is superclass and overridden method in the subclass should have the same declaration signature such
as parameters list, type, and return type.
Two important usages of method overriding in Java:
1. Method overriding is used for achieving run-time polymorphism.
2. Method overriding is used for writing specific definition of a subclass method (this method is known as the
overridden method).
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move(); // runs the method in Animal class
b.move(); // runs the method in Dog class
Rules for Method Overriding:
1. The argument list should be exactly the same as that of the overridden method.
2. The return type should be the same or a subtype of the return type declared in the original
overridden method in the superclass.
3. The access level cannot be more restrictive than the overridden method's access level. For
example: If the superclass method is declared public then the overridding method in the sub
class cannot be either private or protected.
4. Instance methods can be overridden only if they are inherited by the subclass.
5. A method declared final cannot be overridden.
6. A method declared static cannot be overridden but can be re-declared.
7. If a method cannot be inherited, then it cannot be overridden.
8. A subclass within the same package as the instance's superclass can override any superclass
method that is not declared private or final.
9. A subclass in a different package can only override the non-final methods declared public or
protected.
10. An overriding method can throw any uncheck exceptions, regardless of whether the
overridden method throws exceptions or not. However, the overriding method should not throw
checked exceptions that are new or broader than the ones declared by the overridden method.
The overriding method can throw narrower or fewer exceptions than the overridden method.
11. Constructors cannot be overridden.
final Keyword in Java
The final Keyword in Java is used as a non-access modifier applicable to a variable, a method, or
a class. It is used to restrict a user in Java. We cannot use the final keyword in a block. It restricts the
user from accessing that particular part of the program, such as restricting the modification and
inheriting the properties from the parent class or overloading.
The following are different contexts where the final is used:
1. Variable
2. Method
3. Class
Characteristics of final keyword in Java:
Final variables: Declaring a variable as final prevents its value from being changed after
initialization, useful for constants.
Final methods: When a method is declared as final, it cannot be overridden by a subclass.
This is useful for methods that are part of a class’s public API and should not be modified by
subclasses.
Final classes: When a class is declared as final, it cannot be extended by a subclass. This is
useful for classes that are intended to be used as is and should not be modified or extended.
Initialization: Final variables must be initialized either at the time of declaration or in the
constructor of the class. This ensures that the value of the variable is set and cannot be changed.
Performance: The use of a final can sometimes improve performance, as the compiler can
optimize the code more effectively when it knows that a variable or method cannot be changed.
Security: The final can help improve security by preventing malicious code from modifying
sensitive data or behavior.
Java Final Variable
When a variable is declared with the final keyword, its value can’t be changed, essentially, a constant.
This also means that you must initialize a final variable.
If the final variable is a reference, this means that the variable cannot be re-bound to reference another
object, but the internal state of the object pointed by that reference variable can be changed i.e. you
can add or remove elements from the final array or final collection.
public class ConstantExample {
public static void main(String[] args) {
// Define a constant variable PI
final double PI = 3.14159;
// Print the value of PI
System.out.println("Value of PI: " + PI);
}
}
Java Final classes
When a class is declared with the final keyword in Java, it is called a final class. A final class cannot
be extended(inherited).
There are two uses of a final class:
Usage 1: One is definitely to prevent inheritance, as final classes cannot be extended. For example,
all Wrapper Classes like Integer, Float, etc. are final classes. We can not extend them.
final class A
// methods and fields
// The following class is illegal
class B extends A
// COMPILE-ERROR! Can’t subclass A
Usage 2: The other use of final with classes is to create an immutable class like the
predefined String class. One can not make a class immutable without making it final.
Java Final Method
When a method is declared with final keyword, it is called a final method in Java. A final
method cannot be overridden.
The Object class does this—a number of its methods are final. We must declare
methods with the final keyword for which we are required to follow the same
implementation throughout all the derived classes.
class A
final void m1()
System.out.println(“This is a final method.”);
class B extends A
{
void m1()
// Compile-error! We can not override
System.out.println(“Illegal!”);
Advantages of final Keyword in Java:
The final keyword in Java provides several advantages, including:
Ensuring immutability:
When a variable or reference is marked as final, its value cannot be changed once it is
assigned. This helps ensure that data is immutable and cannot be accidentally or
maliciously modified.
Improving performance:
The use of the final can sometimes help improve performance, as the Java Virtual
Machine (JVM) can optimize code more effectively when it knows that certain values or
references cannot be changed.
Making code easier to understand:
By declaring variables, methods, or classes as final, developers can make their code
easier to understand and reason about. When a value or reference is marked as final, it
is clear that it will not change, which can simplify code analysis and debugging.
Promoting code reuse:
By declaring methods as final, developers can prevent subclasses from overriding them.
This can help promote code reuse and reduce duplication, as subclasses must use the
parent class’s implementation of the method.
Enhancing security:
The use of final can help enhance security by preventing malicious code from modifying
sensitive data or behavior.
Access Modifiers in Java:
There are four access modifiers in java: These are public, private, default, and
protected.
Let us discuss various scenarios of accessing protected members which are listed below
as follows:
1. Accessing in the same class
2. Accessing in other classes of the same package
3. Accessing protected members of a class in its subclass in the same package
4. Accessing another class in a different package
5. Accessing in sub-class in a different package
Case 1: Accessing protected members in the same class
We can access protected members of a class anywhere in it.
class Sample {
protected int year = 2021;
protected void printYear()
{
System.out.println("Its " + year + " !!");
}
public static void main(String[] args)
{
Sample sample = new Sample();
System.out.println(sample.year);
sample.printYear();
}
}
Case 2: Accessing protected members in other classes of the same package
We can access protected members of a class in another class that is present in
the same package.
class Sample {
protected int year = 2021;
protected void printYear() {
System.out.println("Its "+year+" !!");
}
}
// Class 2
public class Test {
// Main driver method
public static void main(String[] args) {
Sample sample = new Sample();
System.out.println(sample.year);
sample.printYear();
}
}
Case 3: Accessing protected members of a class in its subclass in the same package
We can access protected members of a class in its subclass if both are present in the
same package.
class Sample {
static protected String title = "geekforgeeks";
protected int year = 2021;
protected void printYear() {
System.out.println("Its "+year+" !!");
// Class 2
public class Test extends Sample {
public static void main(String[] args) {
Sample sample = new Sample();
System.out.println(sample.year);
sample.printYear();
System.out.println(Sample.title);
}
Case 4: Accessing protected members in another class in a different package
We cannot access the protected members of a class in a class (non-subclass) that is
present in a different package.
package package1;
// Main class
public class Sample {
static protected String title = "geeksforgeeks";
protected int year = 2021;
// Protected method
protected void printYear() {
System.out.println("Its "+year+" !!");
}
}
package package2;
// Importing above package
import package1.Sample;
// Main class
public class Test {
// Main driver method
public static void main(String[] args) {
Sample sample = new Sample();
System.out.println(sample.year);
sample.printYear();
System.out.println(Sample.title);
}
Output:
error: year has protected access in Sample
System.out.println(sample.year);
error: printYear() has protected access in Sample
sample.printYear();
error: title has protected access in Sample
System.out.println(Sample.title);
It will give a compile-time error. In the following example, we will create two classes.
Sample class in package1 and Test class in package2 and try to access protected
members of Sample class in Test class. It is justified in the above two examples.
Case 5: Accessing protected members in sub-class in a different package
We can access protected members of a class in its subclass present in a different
package. In the following example, we will create two classes.
Sample class in package1 and Child class in package2. Child class extends Sample
class.
package package1;
// Class
public class Sample {
// Protected attributes
static protected String title = "geeksforgeeks";
protected int year = 2021;
protected void printYear()
System.out.println("Its " + year + " !!");
package package2;
// Importing class from above package
import package1.Sample;
// Main class
public class Child extends Sample {
// Method 1
void helper()
System.out.println(year);
printYear();
System.out.println(Sample.title);
// Method 2
// Main driver method
public static void main(String[] args)
// Creating child class instance inside main()
Child child = new Child();
child.helper();
Constructors in Java :
In Java, a constructor is a special method used to initialize objects.
1. Unlike regular methods, constructors are invoked when an instance of a
class is created.
2. They have the same name as the class and do not have a return type.
3. Constructors are essential for setting initial values for object attributes and
preparing the object for use.
Types of Constructors
1. Default Constructor
A default constructor is automatically provided by the Java compiler if no constructors are explicitly
defined in the class. It initializes the object with default values.
2. No-Argument Constructor
A no-argument constructor is explicitly defined by the programmer and does not take any
parameters. It is similar to the default constructor but can include custom initialization code.
3. Parameterized Constructor
A parameterized constructor accepts arguments to initialize an object with specific values. This
allows for more flexible and controlled initialization of object attributes.
4. Copy Constructor
A copy constructor is used to create a new object as a copy of an existing object. Java does not
provide a default copy constructor; however, it can be implemented manually.
Syntax:
class ClassName
{
// Constructor
ClassName()
{
// Initialization code
}
// Parameterized Constructor
ClassName(dataType parameter1, dataType parameter2)
{
// Initialization code using parameters
}
// Copy Constructor
ClassName(ClassName obj)
{
// Initialization code to copy attributes
}
}
Example 1: Default Constructor
public class Car
String model;
int year;
// Default Constructor
public Car()
{
model = "Unknown";
year = 0;
public static void main(String[] args)
Car car = new Car();
System.out.println("Model: " + car.model + ", Year: " + car.year);
Example 2: Parameterized Constructor
public class Car
String model;
int year;
// Parameterized Constructor
public Car(String model, int year)
this.model = model;
this.year = year;
public static void main(String[] args) {
Car car = new Car("Toyota", 2021);
System.out.println("Model: " + car.model + ", Year: " + car.year);
Example 3: Constructor Overloading
public class Car {
String model;
int year;
// No-Argument Constructor
public Car() {
model = "Unknown";
year = 0;
// Parameterized Constructor
public Car(String model, int year) {
this.model = model;
this.year = year;
public static void main(String[] args) {
Car car1 = new Car();
Car car2 = new Car("Honda", 2022);
System.out.println("Car1 -> Model: " + car1.model + ", Year: " + car1.year);
System.out.println("Car2 -> Model: " + car2.model + ", Year: " + car2.year);
Constructor Naming: Ensure the constructor name matches the class name exactly,
including case sensitivity.
Avoid Logic in Constructors: Keep constructors simple and avoid complex logic. Use
methods for complex initialization.
Use this Keyword: Use the this keyword to differentiate between class attributes and
parameters with the same name.
Constructor Chaining: Use constructor chaining to avoid code duplication by calling
one constructor from another within the same class using this().
Immutable Objects: Consider using constructors to create immutable objects by not
providing setters for the attributes initialized in the constructor.
Exception Handling: Handle exceptions within constructors to ensure the object is in a
valid state after creation.
Abstract Classes and Methods:
Data abstraction is the process of hiding certain details and showing only essential
information to the user.
Abstraction can be achieved with either abstract classes or interfaces
The abstract keyword is a non-access modifier, used for classes and methods:
Abstract class: is a restricted class that cannot be used to create objects (to access
it, it must be inherited from another class).
Abstract method: can only be used in an abstract class, and it does not have a
body. The body is provided by the subclass (inherited from).
Note : An abstract class can have both abstract and regular methods:
Syntax:
abstract class Brake
{
public abstract void display(); // abstract method
public void disp(){} // non abstract method
}
Brake b = new Brake(); // will give compile time error because the class is declared as
abstract.
To access the abstract class, it must be inherited from another class.
Why And When To Use Abstract Classes and Methods?
To achieve security - hide certain details and only show the important details of an object.
Interfaces
Another way to achieve abstraction in Java, is with interfaces.
An interface is a completely "abstract class" that is used to group related methods with
empty bodies:
Basically interface concept is used for achieving the multiple inheritance in java.
To access the interface methods, the interface must be "implemented" by another class
with the implements keyword (instead of extends). The body of the interface method is
provided by the "implement" class:
Notes on Interfaces:
Like abstract classes, interfaces cannot be used to create objects
Interface methods do not have a body - the body is provided by the "implement" class
On implementation of an interface, you must override all of its methods
Interface methods are by default abstract and public
Interface attributes are by default public, static and final
An interface cannot contain a constructor (as it cannot be used to create objects)
Why And When To Use Interfaces?
1) To achieve security - hide certain details and only show the important details of an object
(interface).
2) Java does not support "multiple inheritance" (a class can only inherit from one
superclass). However, it can be achieved with interfaces, because the class
can implement multiple interfaces.
Syntax to create interface:
interface interface_name
// variables and methods can be declared here
Where interface is the keyword which is used to declare the interface
Interface_name : any name according to the rules.
Example:
Multiple Interfaces Implemented by the class
Note : one interface can extend another interface instead of implements
interface FirstInterface
{ public void myMethod(); // interface method
interface SecondInterface extends FirstInterface
{ public void myOtherMethod(); // interface method
Class vs Interface
The following table lists all the major differences between an interface and a class in
Java.
Features Class Interface
The keyword used to create a The keyword used to create an
Keyword class is “class”. interface is “interface”.
An interface cannot be instantiated
A class can be instantiated, i.e.,
directly, instead, it is implemented by
objects of a class can be created.
Instantiation a class or a struct.
Classes do not support multiple Interface supports multiple
Inheritance inheritance. inheritance.
A class can implement an interface
A class can inherit another class
Inheritance using the keyword “implements”. An
using the keyword extends.
Mechanism interface can inherit another interface
Features Class Interface
using “extends”.
Constructors It can contain constructors. It cannot contain constructors.
An interface contains abstract
Methods in a class can be methods by default (before Java 8) or
abstract, concrete, or both. default/static methods (from Java 8
Methods onward).
Variables and methods in a class
can be declared using any access All variables and methods in an
Access specifier(public, private, default, interface are declared public
Specifiers protected).
Variables in a class can be static,
All variables are static and final.
Variables final, or neither.
An interface specifies a contract for
A class is a blueprint for creating
classes to implement by focusing on
objects and encapsulates data and
capabilities rather than
behaviour.
Purpose implementation.
Object cloning in Java refers to creating an exact copy of an object. The clone()
method in Java is used to clone an object. It creates a new instance of the class of the
current object and initializes all its fields with exactly the contents of the corresponding
fields of this object.
class myclass implements Cloneable {
int x, y;
// Constructor to initialize object fields
myclass() {
x = 10;
y = 20;
// Overriding the clone() method
@Override
public Object clone() throws CloneNotSupportedException {
// Returning a clone of the current object
return super.clone();
public class Main {
public static void main(String[] args)
throws CloneNotSupportedException {
myclass o1 = new myclass();
// Cloning obj1 into obj2
myclass o2 = (myclass) o1.clone();
System.out.println("o1: " + o1.x + " " + o1.y);
System.out.println("o2: " + o2.x + " " + o2.y);
Output
o1: 10 20
o2: 10 20
Set Classpath in Java:
CLASSPATH describes the location where all the required files are available which are
used in the application. Java Compiler and JVM (Java Virtual Machine) use
CLASSPATH to locate the required files. If the CLASSPATH is not set, Java Compiler
will not be able to find the required files and hence will throw the following error.
Error: Could not find or load main class <class name> (e.g. GFG)
import java.io.*;
class GFG {
public static void main(String[] args)
{
// prints hello students to the console
System.out.println("hello students !");
}
}
Set the CLASSPATH in JAVA in Windows
Open the Command Prompt.
Use the following command to set the CLASSPATH:
set CLASSPATH=.;C:\path\to\your\classes;C:\path\to\your\libraries
Note: The dot (.) represents the current directory, and the semicolon (;) is used as a
separator between different paths.
Example:
set CLASSPATH=.;C:\Users\GFG\JavaClasses;C:\Program Files\Java\libs
GUI:
1. Select Start
2. Go to the Control Panel
3.. Select System and Security
4.. Select Advanced System settings
5.. Click on Environment Variables
6.. Click on New under System Variables
7.. Add CLASSPATH as variable name and path of files as a variable value.
8.. Select OK.
Static import in Java
In Java, static import concept is introduced in 1.5 version. With the help of static import,
we can access the static members of a class directly without class name or any object.
According to SUN microSystem, it will improve the code readability and enhance coding.
But according to the programming experts, it will lead to confusion and not good for
programming. If there is no specific requirement then we should not go for static import.
Advantage of static import:
If user wants to access any static member of class then less coding is required.
Disadvantage of static import:
Static import makes the program unreadable and unmaintainable if you are reusing this
feature, especially in large codebases or projects with multiple developers.
class static_import {
public static void main(String[] args)
{
System.out.println(Math.sqrt(4));
System.out.println(Math.pow(2, 2));
System.out.println(Math.abs(6.3));
}
}
Output:
2.0
4.0
6.3
import static java.lang.Math.*;
class Test2 {
public static void main(String[] args)
{
System.out.println(sqrt(4));
System.out.println(pow(2, 2));
System.out.println(abs(6.3));
}
}
Output:
2.0
4.0
6.3
NOTE : System is a class present in java.lang package and out is a static variable
present in System class. By the help of static import we are calling it without class name.
Ambiguity in static import:
If two static members of the same name are imported from multiple different classes, the
compiler will throw an error, as it will not be able to determine which member to use in
the absence of class name qualification.
import static java.lang.Integer.*;
import static java.lang.Byte.*;
public class Static_Import_Issues {
public static void main(String[] args)
{
system.out.println(MAX_VALUE);
}
}
Error:Reference to MAX_VALUE is ambiguous
Difference between import and static import:
With the help of import, we are able to access classes and interfaces which are
present in any package. But using static import, we can access all the static members
(variables and methods) of a class directly without explicitly calling class name.
The main difference is Readability, ClassName.dataMember (System.out) is less
readable when compared to dataMember(out), static import can make your program
more readable by eliminating repetitive class names and making code more concise.