Object-Oriented Programming in
Java
Core Concepts: Class, Object, Encapsulation, Inheritance,
Polymorphism, Abstraction
1. Introduction to Object-Oriented Programming
Object-Oriented Programming (OOP) is a programming paradigm
centered around the concept of objects, which bundle data
(attributes) and behaviour (methods) together into a single unit.
Unlike procedural programming, where the focus is on functions
and the sequence of instructions, OOP models real-world entities
as software objects that interact with one another through
well-defined interfaces.
Java is a purely object-oriented language (with the exception of
primitive data types) and was designed with the philosophy of
'write once, run anywhere'. Every piece of executable Java code
lives inside a class, and objects are instances of these classes
created at runtime using the 'new' keyword.
The four foundational pillars of OOP — Encapsulation,
Inheritance, Polymorphism, and Abstraction — allow developers to
build modular, reusable, and maintainable software systems.
These pillars reduce code duplication, improve testability, and
make large systems easier to reason about.
Key Terms: Object • Class • Instance • Paradigm • Bytecode • JVM
2. Classes and Objects
A class is a blueprint or template that defines the structure and
behaviour that its objects will have. It specifies fields (also called
instance variables) to hold state, and methods to define behaviour.
An object is a concrete instantiation of a class, occupying its own
memory in the heap.
Every class in Java can have constructors — special methods
used to initialize objects at the time of creation. If no constructor is
defined explicitly, Java automatically provides a no-argument
default constructor. Constructors can be overloaded to allow
multiple ways of initializing an object.
Access modifiers (private, default, protected, public) control the
visibility of class members. Choosing the right level of visibility is
essential to enforcing encapsulation and preventing external code
from directly manipulating internal object state.
● public class Student { private String name; private int rollNo; }
● Student s1 = new Student(); // object creation using the new
operator
● Constructors share the class name and have no return type
● 'this' keyword refers to the current object instance
Key Terms: Constructor • Access Modifier • Instance Variable •
Heap Memory
3. Encapsulation
Encapsulation is the mechanism of wrapping data and the
methods that operate on that data into a single unit, and restricting
direct access to some of an object's components. In Java, this is
achieved by declaring instance variables as private and exposing
controlled access through public getter and setter methods.
The primary benefit of encapsulation is data hiding: internal
representation of an object can change without affecting external
code that depends on it, as long as the public interface (the getters
and setters) remains stable. This also allows validation logic to be
centralized inside setter methods, preventing invalid object states.
A well-encapsulated class, sometimes referred to as a POJO
(Plain Old Java Object) or JavaBean, typically has private fields, a
no-argument constructor, and public accessor methods following
the getXxx()/setXxx() naming convention.
Concept Description
Data Hiding Restricting direct access to fields using private modifier
Getter Method Public method that returns the value of a private field
Setter Method Public method that validates and updates a private field
JavaBean A reusable class following encapsulation naming conventions
Key Terms: Data Hiding • Getter • Setter • JavaBean
4. Inheritance
Inheritance allows a new class (subclass/child class) to acquire
the properties and behaviours of an existing class
(superclass/parent class), promoting code reuse. In Java,
inheritance is implemented using the 'extends' keyword for classes
and 'implements' for interfaces.
Java supports single inheritance for classes (a class can extend
only one superclass) to avoid the diamond problem, but supports
multiple inheritance of type through interfaces. The 'super'
keyword is used within a subclass to refer to members of its
immediate superclass, including invoking the superclass
constructor.
Java supports several forms of inheritance: single inheritance (one
parent, one child), multilevel inheritance (a chain of classes), and
hierarchical inheritance (multiple child classes derived from one
parent). Method overriding, where a subclass provides its own
implementation of a method already defined in its superclass, is a
key feature enabled by inheritance.
● class Animal { void sound() { } }
● class Dog extends Animal { void sound() {
[Link]("Bark"); } }
● [Link]() invokes the parent class version of an
overridden method
● The 'final' keyword on a class prevents it from being
subclassed
Key Terms: Superclass • Subclass • extends • super • Method
Overriding
5. Polymorphism
Polymorphism, meaning 'many forms', allows a single interface or
method name to represent different underlying behaviours. Java
supports two types of polymorphism: compile-time (static)
polymorphism achieved through method overloading, and runtime
(dynamic) polymorphism achieved through method overriding.
Method overloading occurs when multiple methods in the same
class share the same name but differ in the number or type of
parameters. The compiler resolves which method to invoke based
on the method signature at compile time.
Runtime polymorphism is achieved when a subclass overrides a
method of its superclass, and a superclass reference variable
holding a subclass object invokes the overridden version. This is
resolved dynamically at runtime via a mechanism called dynamic
method dispatch, which underlies much of Java's flexibility in
designing extensible systems.
Type Mechanism Resolved At
Compile-time Method Overloading Compile time
Runtime Method Overriding Runtime (dynamic dispatch)
Key Terms: Overloading • Overriding • Dynamic Dispatch • Runtime
Binding
6. Abstraction
Abstraction focuses on exposing only the essential features of an
object while hiding the implementation details. Java provides two
mechanisms to achieve abstraction: abstract classes and
interfaces.
An abstract class, declared using the 'abstract' keyword, may
contain both abstract methods (without a body) and concrete
methods (with implementation). It cannot be instantiated directly
and must be subclassed. Interfaces, on the other hand,
traditionally define a contract of method signatures that
implementing classes must fulfil; since Java 8, interfaces can also
contain default and static methods with implementations.
Choosing between an abstract class and an interface depends on
the design requirement: abstract classes are suited when classes
share a common base implementation, while interfaces are
preferred when unrelated classes need to guarantee a common
capability, such as Comparable or Runnable.
Key Terms: Abstract Class • Interface • Contract • Default Method
7. Exception Handling and Packages
Java uses a robust exception handling mechanism built around
try, catch, finally, throw, and throws to manage runtime errors
gracefully without crashing the program. Exceptions are objects
representing an abnormal condition, and the class hierarchy is
rooted at the Throwable class, branching into Error and Exception.
Checked exceptions (like IOException) must be either caught or
declared using 'throws', while unchecked exceptions (subclasses
of RuntimeException) are not enforced at compile time. Custom
exceptions can be created by extending the Exception class.
Packages in Java are namespaces that organize related classes
and interfaces, preventing naming conflicts and controlling access.
The [Link], [Link], and [Link] packages are among the most
frequently used in application development, and the 'import'
statement is used to bring external package members into scope.
● try { riskyCode(); } catch (Exception e) { handle(e); } finally {
cleanup(); }
● Checked exceptions: IOException, SQLException
● Unchecked exceptions: NullPointerException,
ArrayIndexOutOfBoundsException
● package [Link]; import [Link].*;
Key Terms: Exception • try-catch • Checked/Unchecked • Package
8. Static Members and the 'this' Keyword
The 'static' keyword in Java indicates that a member (variable or
method) belongs to the class itself rather than to any individual
object. Static variables are shared across all instances of the class
and are initialized only once when the class is loaded by the JVM,
making them useful for counters, constants, and utility values
common to every object.
Static methods can be invoked directly using the class name
without creating an object, and they cannot access non-static
(instance) members directly because they do not operate on a
particular object instance. The main() method in Java is declared
static precisely because the JVM needs to invoke it before any
object of the class exists.
The 'this' keyword refers to the current object within an instance
method or constructor. It is commonly used to resolve naming
conflicts between instance variables and constructor/method
parameters, and to enable constructor chaining using this(...)
syntax within overloaded constructors.
● static int count = 0; // shared across all objects
● public static void main(String[] args) { ... } // entry point
● [Link] = name; // resolves parameter/field name conflict
● Static blocks execute once when the class is first loaded into
memory
Key Terms: static • this • Class Variable • Instance Variable • JVM
9. Real-World Applications and Best Practices
OOP principles in Java are widely used to model real-world
systems such as banking applications, e-commerce platforms,
hospital management systems, and college ERP software, where
entities like Account, Product, Patient, and Student map naturally
onto classes. This close correspondence between real-world
entities and code structures is one of the strongest arguments in
favour of the object-oriented approach for large, evolving systems.
Good OOP design follows established principles such as SOLID
(Single Responsibility, Open-Closed, Liskov Substitution, Interface
Segregation, Dependency Inversion), which guide developers
toward writing code that is easier to extend, test, and maintain
over the software's lifetime.
Common pitfalls to avoid include excessive use of public fields
(breaking encapsulation), deep inheritance hierarchies (which
increase coupling and reduce flexibility), and God classes that try
to do too much. Favouring composition over inheritance, where
appropriate, often leads to more flexible and maintainable designs.
Principle Meaning
Single Responsibility A class should have only one reason to change
Open-Closed Open for extension, closed for modification
Liskov Substitution Subtypes must be substitutable for their base types
Composition over Inheritance Prefer building behaviour via object composition
Key Terms: SOLID • Composition • Coupling • Software Design