Java OOP Principles
Object-Oriented Programming (OOP) is a programming paradigm that organizes software design around data, or objects, rather than functions and logic. Java is a purely object-oriented language, meaning almost everything in Java revolves around classes and objects.
The core idea behind OOP is to model real-world entities as objects, which have both state (data/attributes) and behavior (methods/functions). This approach aims to make software more modular, reusable, understandable, and maintainable.
Core OOP Principles in Java
OOP in Java is built upon four fundamental pillars:
- Encapsulation
- Abstraction
- Inheritance
- Polymorphism
Let's explore each of these:
1. Encapsulation
Definition: Encapsulation is the bundling of data (attributes) and the methods that operate on the data into a single unit (a class). It also involves restricting direct access to some of an object's components, meaning internal representation of an object is hidden from the outside.
How Java achieves it:
- By declaring instance variables (data) as
private
. - By providing public
getter
andsetter
methods to access and modify these private variables.
Example:
public class BankAccount {
private String accountNumber; // Encapsulated data
private double balance; // Encapsulated data
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
// Public getter methods
public String getAccountNumber() {
return accountNumber;
}
public double getBalance() {
return balance;
}
// Public setter/behavior methods
public void deposit(double amount) {
if (amount > 0) {
this.balance += amount;
System.out.println("Deposited: " + amount);
}
}
public void withdraw(double amount) {
if (amount > 0 && this.balance >= amount) {
this.balance -= amount;
System.out.println("Withdrew: " + amount);
} else {
System.out.println("Insufficient balance or invalid amount.");
}
}
}
In this example, accountNumber
and balance
are private, so they can only be accessed or modified via the deposit
, withdraw
, getAccountNumber
, and getBalance
methods, providing controlled access.
2. Abstraction
Definition: Abstraction is the process of hiding the complex implementation details and showing only the essential features of an object. It focuses on what an object does rather than how it does it.
How Java achieves it:
- Abstract Classes: Classes declared with the
abstract
keyword. They cannot be instantiated directly and can have both abstract (without implementation) and concrete (with implementation) methods. - Interfaces: Blueprints of a class. They contain only abstract methods (prior to Java 8) and constants. From Java 8 onwards, they can have default and static methods. A class implements an interface, promising to provide concrete implementations for its abstract methods.
Example (using Abstract Class):
// Abstract Class
abstract class Shape {
abstract double getArea(); // Abstract method (no implementation)
public void display() { // Concrete method
System.out.println("This is a shape.");
}
}
// Concrete class implementing Shape
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
double getArea() { // Implementation of abstract method
return Math.PI * radius * radius;
}
}
// Example (using Interface):
interface Drivable {
void start(); // Abstract method
void stop(); // Abstract method
}
class Car implements Drivable {
@Override
public void start() {
System.out.println("Car started.");
}
@Override
public void stop() {
System.out.println("Car stopped.");
}
}
Here, Shape
and Drivable
abstract the common behavior getArea()
, start()
, stop()
without revealing the internal calculations or mechanisms.
3. Inheritance
Definition: Inheritance is a mechanism where one class (subclass/child class) acquires the properties and behaviors (fields and methods) of another class (superclass/parent class). It promotes code reusability and establishes an "is-a" relationship.
How Java achieves it:
- Using the
extends
keyword. A class can extend only one other class (single inheritance). - Interfaces can also be extended by other interfaces.
Example:
// Parent Class (Superclass)
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + " is eating.");
}
}
// Child Class (Subclass) inheriting from Animal
class Dog extends Animal {
public Dog(String name) {
super(name); // Call parent class constructor
}
public void bark() {
System.out.println(name + " is barking.");
}
}
// Another Child Class
class Cat extends Animal {
public Cat(String name) {
super(name);
}
public void meow() {
System.out.println(name + " is meowing.");
}
}
Here, Dog
and Cat
inherit the name
field and eat()
method from Animal
, reusing common functionalities.
4. Polymorphism
Definition: Polymorphism means "many forms." It allows objects of different classes to be treated as objects of a common type. It enables a single interface to represent different underlying forms (data types or classes).
How Java achieves it:
- Method Overloading (Compile-time Polymorphism): Defining multiple methods in the same class with the same name but different parameters (number, type, or order of arguments).
- Method Overriding (Runtime Polymorphism): Defining a method in a subclass that has the same signature (name, return type, and parameters) as a method in its superclass. This allows a subclass to provide a specific implementation of a method that is already defined in its superclass.
Example (Method Overloading):
class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) { // Overloaded method
return a + b;
}
public int add(int a, int b, int c) { // Overloaded method
return a + b + c;
}
}
The add
method takes different forms based on the arguments.
Example (Method Overriding & Runtime Polymorphism):
class Vehicle {
public void speedUp() {
System.out.println("Vehicle speeding up.");
}
}
class Car extends Vehicle {
@Override
public void speedUp() { // Overridden method
System.out.println("Car accelerating.");
}
}
class Bicycle extends Vehicle {
@Override
public void speedUp() { // Overridden method
System.out.println("Bicycle pedaling faster.");
}
}
public class PolyDemo {
public static void main(String[] args) {
Vehicle myCar = new Car(); // Polymorphic reference
Vehicle myBicycle = new Bicycle(); // Polymorphic reference
myCar.speedUp(); // Calls Car's speedUp()
myBicycle.speedUp(); // Calls Bicycle's speedUp()
Vehicle genericVehicle = new Vehicle();
genericVehicle.speedUp(); // Calls Vehicle's speedUp()
}
}
Output:
Car accelerating.
Bicycle pedaling faster.
Vehicle speeding up.
Here, myCar
and myBicycle
are declared as Vehicle
type but behave differently based on their actual object type at runtime.
Other Key OOP Concepts in Java
- Class: A blueprint or template for creating objects. It defines the common attributes and behaviors that all objects of that class will have.
- Object: An instance of a class. It's a concrete entity created from a class, representing a real-world item.
- Constructor: A special method in a class that is automatically called when an object of that class is created (instantiated). Its primary purpose is to initialize the object's state.
Benefits of OOP
- Modularity: Breaking down complex systems into smaller, manageable, and independent objects.
- Reusability: Inheritance allows code reuse, reducing development time and effort.
- Maintainability: Easier to locate, fix, and update issues due to modular structure.
- Scalability: Easier to add new features or expand functionality without affecting existing code.
- Flexibility: Polymorphism allows for more flexible and adaptable code.
- Data Security: Encapsulation protects data from accidental corruption.
In summary, OOP in Java provides a structured and powerful way to design and develop software, making it more robust, maintainable, and scalable by organizing code around real-world objects and their interactions.