Object-Oriented Programming (OOP) is a programming approach that organizes code around objects and classes rather than focusing only on functions and procedures. Java is an object-oriented language that uses OOP concepts to make programs more structured, reusable, and easier to maintain.
In this article, we will explore the fundamentals of OOP in Java, including classes and objects, encapsulation, inheritance, polymorphism, and abstraction. We will also look at constructors, methods, access modifiers, and how OOP differs from procedural programming. By the end, you will have a clear understanding of the core OOP concepts used when developing Java applications.
Table of Contents
What is OOP in Java?
Object-Oriented Programming (OOP) in Java is a programming approach that organizes a program around objects and classes. Instead of writing a program as a collection of separate functions, OOP combines data and the methods that work with that data into objects.
Java is designed around OOP principles, which makes it easier to create programs that are modular, reusable, and easier to maintain.
Example:
Consider a Car object. A car has properties such as its color, model, and speed, and it can perform actions such as start(), stop(), and accelerate().
class Car {
String color;
String model;void start() {
System.out.println("The car has started.");
}
}
Here, the Car class acts as a blueprint for creating car objects. The variables represent the object's data, while the start() method represents its behavior.
We can create an object from this class:
Car myCar = new Car();
myCar.color = "Red";
myCar.model = "Sedan";myCar.start();
In this example, myCar is an object created from the Car class. OOP in Java is mainly built around four core concepts:
- Encapsulation: Bundling data and methods together while controlling access to the data.
- Inheritance: Allowing one class to acquire properties and behaviors from another class.
- Polymorphism: Allowing the same method or interface to behave differently in different situations.
- Abstraction: Hiding unnecessary implementation details and exposing only the essential features.
Together, these concepts help developers build Java programs that are organized, flexible, and easier to manage as they grow.
Why use OOP in Java?
OOP provides a structured way to design Java programs by organizing related data and behavior into classes and objects. This becomes especially useful when applications grow larger and more complex. Some of the main reasons to use OOP in Java are:
- Code Reusability: OOP allows developers to reuse existing code instead of writing the same logic repeatedly. Inheritance and reusable classes make it easier to share common functionality across different parts of a program.
- Better Organization: OOP groups related data and methods together in classes. This makes the code easier to understand and helps developers organize large programs into smaller, manageable components.
- Easier Maintenance: When a program is divided into separate classes and objects, changes can often be made to one part of the program without affecting the entire application. This makes debugging and maintenance easier.
- Data Security: Encapsulation allows developers to control how an object's data can be accessed or modified. Access modifiers such as private can prevent other parts of the program from directly changing sensitive data.
- Flexibility: Concepts such as polymorphism allow the same interface or method to work with different types of objects. This makes Java programs more flexible and easier to extend.
- Easier Development of Large Applications: OOP makes it possible to break a large application into smaller, independent classes. Different parts of an application can then be developed, tested, and modified more easily.
In short, OOP helps Java developers write code that is more organized, reusable, maintainable, and flexible, making it well suited for both small programs and large applications.
Classes and Objects
Classes and objects are the basic building blocks of OOP in Java. A class defines the structure and behavior of an object, while an object is an actual instance of that class.
A class is a blueprint or template used to create objects. It defines the data an object can contain and the actions it can perform.
Example:
class Student {
String name;
int age;void study() {
System.out.println(name + " is studying.");
}
}
Here, Student is a class. It contains two variables, name and age, and a study() method that defines the behavior of a student.
An object is an instance of a class. Once a class has been defined, objects can be created from it using the new keyword.
Example:
Student student1 = new Student();
student1.name = "Alex";
student1.age = 20;student1.study();
In this example, student1 is an object of the Student class. It has its own values for name and age, and it can use the study() method defined in the class.
A class can be used to create multiple objects, with each object maintaining its own data:
Student student1 = new Student();
Student student2 = new Student();student1.name = "Alex";
student2.name = "Sarah";
Both objects belong to the same Student class, but they contain different values.
Class vs Object
Below are the differences between a class and an object:| Basis | Class | Object |
|---|---|---|
| Definition | A class is a blueprint or template used to create objects. | An object is an instance of a class. |
| Purpose | Defines the properties and behaviors that objects can have. | Represents a real instance with its own data and behavior. |
| Creation | A class is declared using the class keyword. | An object is usually created using the new keyword. |
| Memory | A class definition itself does not allocate memory for instance variables. | Memory is allocated when an object is created. |
| Variables | Defines instance variables that objects can have. | Stores actual values for the instance variables. |
| Methods | Defines methods that describe the object's behavior. | Can use the methods defined by its class. |
| Quantity | A program can have one class definition. | Multiple objects can be created from the same class. |
| Example | class Student { } | Student s1 = new Student(); |
| Real-world Example | Student can be considered a blueprint. | s1 can represent one particular student. |
| Relationship | A class defines what an object will contain and do. | An object is created based on a class. |
Encapsulation in Java
Encapsulation is the process of combining data and the methods that operate on that data within a class while restricting direct access to the data.
In Java, encapsulation is commonly achieved by declaring variables as private and providing getter and setter methods to access or modify them.
class Student {
private String name;public void setName(String name) {
this.name = name;
}public String getName() {
return name;
}
}
Here, name cannot be accessed directly from outside the Student class. The setName() and getName() methods control how the data is changed or retrieved.
Why Is Encapsulation Useful?
- Protects Data: Encapsulation keeps an object's data hidden from direct access. By making variables private, you can prevent other parts of the program from changing them directly.
- Provides Controlled Access: Encapsulation allows you to control how data is accessed or modified through methods such as getters and setters. You can add validation before changing a value.
- Improves Data Security: Restricting direct access to important variables reduces the chances of accidental or unwanted changes. This is especially useful when working with sensitive or critical data.
- Makes Code Easier to Maintain: The internal implementation of a class can be changed without affecting the code that uses it. As long as the public methods remain consistent, other parts of the program can continue working normally.
- Improves Code Organization: Encapsulation keeps related data and methods together inside a class. This makes the code more organized, easier to understand, and easier to manage in larger applications.
Inheritance in Java
Inheritance is an OOP concept that allows one class to acquire the properties and methods of another class. It promotes code reuse and allows related classes to share common functionality.
The class that provides the properties and methods is called the parent (superclass), while the class that inherits them is called the child (subclass).
Java uses the extends keyword to implement inheritance:
class Animal {
void eat() {
System.out.println("Animal is eating.");
}
}class Dog extends Animal {
void bark() {
System.out.println("Dog is barking.");
}
}
Here, Dog inherits the eat() method from Animal while also having its own bark() method.
Dog dog = new Dog();
dog.eat(); // Inherited method
dog.bark(); // Dog's own method
Types of Inheritance in Java
Java supports different types of inheritance based on how classes are related to each other.
1. Single Inheritance: In single inheritance, one child class inherits properties and methods from one parent class.
Parent Class
↓
Child Class
Example: Dog inherits from Animal.
2. Multilevel Inheritance: In multilevel inheritance, a class inherits from another child class, forming a chain of inheritance.
Class A
↓
Class B
↓
Class C
Example: BabyDog inherits from Dog, and Dog inherits from Animal.
3. Hierarchical Inheritance: In hierarchical inheritance, multiple child classes inherit from the same parent class.
Parent
/ \
Child 1 Child 2
Example: Both Dog and Cat inherit from Animal.
4. Multiple Inheritance: In multiple inheritance, one child class inherits from multiple parent classes.
Parent A Parent B
\ /
Child
Java does not support multiple inheritance through classes because it can create ambiguity when both parent classes contain methods with the same name. However, Java supports multiple inheritance through interfaces.
5. Hybrid Inheritance: Hybrid inheritance is a combination of two or more types of inheritance, such as hierarchical and multiple inheritance. Java does not support hybrid inheritance through classes because multiple inheritance of classes is not supported. However, similar structures can be created using interfaces.
Polymorphism in Java
Polymorphism means “many forms.” In Java, it allows the same method, operation, or reference to behave differently depending on the object or situation.
Example: A parent class can define a method that is overridden by its child classes:
class Animal {
void sound() {
System.out.println("Animal makes a sound.");
}
}class Dog extends Animal {
void sound() {
System.out.println("Dog barks.");
}
}class Cat extends Animal {
void sound() {
System.out.println("Cat meows.");
}
}
The same sound() method produces different results depending on the object:
Animal a1 = new Dog();
Animal a2 = new Cat();a1.sound(); // Dog barks.
a2.sound(); // Cat meows.
Types of Polymorphism in Java
Polymorphism in Java allows the same method name, interface, or reference to represent different behaviors. Java primarily supports two types of polymorphism.1. Compile-Time Polymorphism: Compile-time polymorphism occurs when the Java compiler determines which method to execute during compilation. It is achieved through method overloading, where methods have the same name but different parameter lists.
Example:
It is also called static polymorphism or early binding.add(int, int) and add(int, int, int).
2. Runtime Polymorphism: Runtime polymorphism occurs when Java determines which overridden method to execute while the program is running. It is achieved through method overriding and generally involves inheritance.
Example:
A Dog class can provide its own implementation of the sound() method inherited from an Animal class.
It is also called dynamic polymorphism or late binding.
Polymorphism makes Java programs more flexible and extensible because the same interface or method can work with different types of objects.
Abstraction in Java
Abstraction is the process of hiding unnecessary implementation details and showing only the essential features of an object. It allows developers to focus on what an object does rather than how it does it.
In Java, abstraction can be achieved using abstract classes and interfaces.
Example:
abstract class Animal {
abstract void sound();void eat() {
System.out.println("Animal is eating.");
}
}class Dog extends Animal {
void sound() {
System.out.println("Dog barks.");
}
}
Here, Animal defines what a subclass should do through the abstract sound() method, while Dog provides the actual implementation.
Why Use Abstraction?
- Hides Implementation Details: Abstraction hides the internal implementation of a class and exposes only the essential functionality. Users can use a feature without needing to know how it works internally.
- Reduces Code Complexity: By showing only the necessary details, abstraction makes complex systems easier to understand. Developers can focus on what an object does rather than how it performs the task.
- Improves Code Maintainability: The internal implementation can be changed without affecting the code that uses the abstraction. This makes applications easier to modify and maintain.
- Promotes Code Reusability: Abstract classes and interfaces allow common behavior to be defined once and reused by multiple classes. This reduces duplicate code and provides a consistent structure.
- Supports Loose Coupling: Abstraction allows classes to depend on general interfaces or abstract classes rather than specific implementations. This makes it easier to replace or extend components without making major changes to the rest of the application.
Constructors vs Methods
Constructors and methods are important parts of Java classes, but they serve different purposes.
|
Feature |
Constructor |
Method |
|---|---|---|
|
Purpose |
A constructor initializes an object when it is created. |
A method defines an action or behaviour that an object can perform. |
|
Name |
It must have the same name as the class. |
It can have any valid name. |
|
Return Type |
It does not have a return type. |
It can have a return type such as int, String, or void. |
|
When It Runs |
It runs automatically when an object is created. |
It runs when it is called. |
| Invocation | Invoked when an object is created using the new keyword. | Invoked using the method name. |
| Object Initialization | Used to initialize instance variables and set the initial state of an object. | Generally used to perform operations on the object's data. |
| Overloading | Can be overloaded by using different parameter lists. | Can be overloaded by using different parameter lists. |
| Overriding | Cannot be overridden. | Can be overridden in a child class. |
| Inheritance | Constructors are not inherited by child classes. | Methods can be inherited by child classes depending on their access modifier. |
| Default Version | Java provides a default constructor if no constructor is explicitly declared. | Java does not automatically provide user-defined methods. |
| Access Modifiers | Can use access modifiers such as public, private, and protected. | Can also use access modifiers such as public, private, and protected. |
| Calling Multiple Times | Normally runs once for each object created. | Can be called multiple times for the same object. |
| Main Use | Sets the initial state of an object. | Performs operations or defines object behavior. |
| Example | Student() { } | void display() { } |
| Keyword | No special keyword is required to declare a constructor. | No special keyword is required to declare a method. |
| Execution Frequency | Executes during object creation. | Can execute whenever the program calls it. |
Example:
class Student {
String name;Student(String name) {
this.name = name;
}void study() {
System.out.println(name + " is studying.");
}
}
Here, Student(String name) is a constructor that initializes the student's name, while study() is a method that defines the student's behavior.
Student student = new Student("Alex");
student.study();
The constructor runs when student is created, while study() runs when it is explicitly called.
Access Modifiers and Data Hiding
Access modifiers control where classes, variables, methods, and constructors can be accessed from. They are an important part of encapsulation and help protect data from unwanted access.
Java provides four main access levels:
1. private: The private modifier provides the highest level of restriction. A private member can be accessed only within the class where it is declared.
class Student {
private int marks = 90;
}
This prevents other classes from directly accessing marks.
2. Default Access: When no access modifier is specified, the member has default (package-private) access. It can be accessed by classes within the same package but not from classes in other packages.
class Student {
int marks = 90;
}
3. protected: The protected modifier allows access within the same package and also allows subclasses in other packages to access the member through inheritance.
class Student {
protected int marks = 90;
}
4. public: The public modifier provides the widest access. A public member can be accessed from any class, provided the class itself is accessible.
class Student {
public int marks = 90;
}
Data hiding is the practice of restricting direct access to an object's internal data and allowing it to be accessed or modified through controlled methods. In Java, data hiding is commonly achieved by:
- Declaring variables as private.
- Providing public getter and setter methods when controlled access is required.
- Adding validation inside setter methods.
class Student {
private int marks;
public void setMarks(int marks) {
if (marks >= 0 && marks <= 100) {
this.marks = marks;
} else {
System.out.println("Invalid marks");
}
}
public int getMarks() {
return marks;
}
}
public class Main {
public static void main(String[] args) {
Student student = new Student();
student.setMarks(85);
System.out.println("Marks = " + student.getMarks());
}
}
Output:
Marks = 85
Explanation:
Here, marks is declared as private, so it cannot be accessed directly from the Main class. Instead:
- setMarks() controls how a value is assigned.
- The if condition ensures that marks remain between 0 and 100.
- getMarks() provides controlled access to the stored value.
- This prevents invalid data from being assigned directly.
For example, this would not be allowed:
student.marks = 150;
because marks is private.
OOP vs Procedural Programming
OOP and procedural programming are two different approaches to organizing code. OOP focuses on objects and classes, while procedural programming focuses on functions and a sequence of instructions.
| Feature | Object-Oriented Programming (OOP) | Procedural Programming |
|---|---|---|
| Basic Approach | Organizes programs around objects and classes. | Organizes programs around procedures or functions. |
| Main Focus | Focuses on objects, their data, and behavior. | Focuses on functions and the sequence of operations. |
| Program Structure | Divided into classes and objects. | Divided into functions or procedures. |
| Data and Functions | Data and methods are grouped together inside classes. | Data and functions are generally handled separately. |
| Data Security | Provides data hiding through encapsulation and access modifiers. | Provides less direct support for data hiding. |
| Reusability | Supports inheritance, composition, and polymorphism for code reuse. | Reuses code mainly through functions and procedures. |
| Inheritance | Supports inheritance. | Does not provide inheritance as a core feature. |
| Polymorphism | Supports compile-time and runtime polymorphism. | Does not provide object-oriented polymorphism. |
| Encapsulation | Supports encapsulation by combining data and methods in classes. | Does not use encapsulation in the same object-oriented sense. |
| Abstraction | Supports abstraction using abstract classes and interfaces. | Generally relies on functions and procedural decomposition rather than OOP abstraction mechanisms. |
| Data Access | Access can be controlled using private, protected, and public. | Data is typically accessed through variables and functions according to the language's rules. |
| Code Maintenance | Easier to maintain large applications when classes are well designed. | Can become difficult to maintain as the program grows and functions increase. |
| Scalability | Well suited for large and complex applications. | Generally better suited for small to medium-sized programs. |
| Problem Solving | Models real-world entities as objects. | Breaks a problem into a sequence of procedures or steps. |
| Examples | Java, C++, C#, Python | C, Pascal, Fortran |
| Common Use Cases | Enterprise applications, GUI applications, games, large software systems. | System utilities, embedded programs, simple scripts, algorithm-focused programs. |
| Example | Student class containing student data and methods. | calculateMarks() and displayMarks() functions operating on student data. |
Real World Applications of OOP
OOP is widely used in Java to build applications that are easier to organize, maintain, and expand.
Some common applications include:
For example, a BankAccount class can contain account details and methods such as deposit(), withdraw(), and checkBalance().
OOP concepts used: Encapsulation, inheritance, abstraction, and polymorphism.
2. E-Commerce Applications: Online shopping platforms use OOP to represent products, customers, shopping carts, orders, and payments.
For example, different product types can inherit common properties from a Product class while providing their own specific behavior.
OOP concepts used: Inheritance, polymorphism, encapsulation, and abstraction.
3. Banking and Payment Systems: Payment applications need to support different payment methods such as credit cards, debit cards, bank transfers, and digital wallets.
An interface such as Payment can define common operations, while each payment type provides its own implementation.
OOP concepts used: Interfaces, abstraction, and runtime polymorphism.
4. Mobile Applications: Java has been widely used for Android application development. OOP helps developers organize applications into classes representing screens, users, services, data models, and other components.
For example, a User class can store user information and provide methods for managing that information.
OOP concepts used: Classes, objects, encapsulation, inheritance, and polymorphism.
5. Game Development: Java-based games can use objects to represent players, enemies, weapons, characters, and game levels.
For example, a common Character class can define basic behavior, while classes such as Warrior and Archer can provide specialized behavior.
OOP concepts used: Inheritance, polymorphism, abstraction, and encapsulation.
Conclusion
OOP is one of the core concepts behind Java programming. By understanding classes, objects, encapsulation, inheritance, polymorphism, and abstraction, you can write Java programs that are more organized, reusable, and easier to maintain.
These concepts form the foundation for learning more advanced Java programming and developing larger applications.
Frequently Asked Questions
1. What is OOP in Java?
OOP is a programming approach that organizes Java programs around classes and objects.
2. What are the four pillars of OOP?
The four pillars are encapsulation, inheritance, polymorphism, and abstraction.
3. What is the difference between a class and an object?
A class is a blueprint that defines an object's structure and behavior, while an object is an instance of that class.
4. Why is OOP used in Java?
OOP helps make Java programs more organized, reusable, flexible, and easier to maintain.
5. Does Java support all OOP concepts?
Yes. Java supports the major OOP concepts, including encapsulation, inheritance, polymorphism, and abstraction.
0 Comments