Page Content

Tutorials

What is the OOP in Java? & Is OOPs in Java easy?

OOP in Java

An effective programming paradigm called object-oriented programming (OOP) arranges programs according to data (objects) as opposed to code (a set of sequential procedures). Code operates on data in traditional process-oriented models, whereas with OOP, code access is controlled by data. There are major organisational advantages to this change, particularly as programs get bigger and more intricate. Java is by definition an object-oriented language, hence all Java programs use some form of object-oriented programming (OOP).

The Fundamentals of OOP (Object-Oriented Programming)

The core ideas of encapsulation, inheritance, and polymorphism are shared by all OOP languages, including Java.

Core Principles of OOP in Java
Core Principles of OOP in Java

Encapsulation

A programming technique known as encapsulation secures code and the data it works with by binding them together, preventing outside meddling and abuse. Through a well defined interface, it controls access to the data and code inside, acting as a protective wrapper. The class is the fundamental unit of encapsulation in Java.

One of the main advantages of encapsulation is information hiding, which conceals a class’s internal operations from outside users. Through the prevention of direct, inappropriate changing of an object’s state, this guarantees data integrity. Declaration of instance variables as private and the provision of public accessor (getter) and mutator (setter) methods for controlled access are how you accomplish this.

Example of Encapsulation: Consider an Employee class where name and salary are private, accessed via public methods.

public class Employee {
    private String name;    // Private instance variable
    private double salary;  // Private instance variable
    // Constructor to initialize
    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }
    // Accessor (getter) method for name
    public String getName() {
        return name;
    }
    // Mutator (setter) method for salary with validation
    public void setSalary(double salary) {
        if (salary > 0) { // Example: enforce positive salary
            this.salary = salary;
        } else {
            System.out.println("Salary cannot be negative.");
        }
    }
    // Accessor (getter) method for salary
    public double getSalary() {
        return salary;
    }
}
public class EncapsulationDemo {
    public static void main(String[] args) {
        Employee emp = new Employee("Alice", 50000.0);
        System.out.println("Name: " + emp.getName());
        System.out.println("Initial Salary: " + emp.getSalary());
        emp.setSalary(55000.0); // Valid change
        System.out.println("Updated Salary: " + emp.getSalary());
        emp.setSalary(-100.0); // Invalid change, demonstrates control
        System.out.println("Salary after invalid attempt: " + emp.getSalary());
    }
}

Code Output:

Name: Alice
Initial Salary: 50000.0
Updated Salary: 55000.0
Salary cannot be negative.
Salary after invalid attempt: 55000.0

In order to prevent direct invalid assignments, this illustrates how the salary can only be altered with setSalary, which also contains a check.

Inheritance

A mechanism known as inheritance enables classes to create hierarchical classifications by acquiring the properties (fields and methods) of other classes. The class doing the inheriting is called the subclass (also known as the child, derived, or extended class), while the class that is inherited is called the superclass (also known as the parent or base class). A subclass is a more specialised form of its superclass that keeps all of its members (private ones excepted) while also adding some of its own particular features.

Given that similar traits and behaviours are defined once in a superclass and subsequently utilised by numerous subclasses, inheritance encourages code reuse and minimises redundancy. To create this relationship in Java, use the extends keyword.

Example of Inheritance: Let’s extend a general Animal class to a more specific Dog class.

// Superclass
class Animal {
    String species;
    public Animal(String species) {
        this.species = species;
    }
    public void eat() {
        System.out.println(species + " is eating.");
    }
}
// Subclass extending Animal
class Dog extends Animal {
    String breed;
    public Dog(String species, String breed) {
        // Calls the constructor of the superclass
        super(species); // The 'super' keyword calls the immediate superclass's constructor [53-56]
        this.breed = breed;
    }
    public void bark() {
        System.out.println(breed + " is barking.");
    }
}
public class InheritanceDemo {
    public static void main(String[] args) {
        Dog myDog = new Dog("Canine", "Golden Retriever");
        System.out.println("My dog is a " + myDog.breed + " " + myDog.species);
        myDog.eat();  // Inherited method
        myDog.bark(); // Dog's specific method
    }
}

Code Output:

My dog is a Golden Retriever Canine
Canine is eating.
Golden Retriever is barking.

This demonstrates how Dog inherits the species field and eat() method from Animal, while also having its own breed field and bark() method. The super() call ensures the Animal part of the Dog object is properly initialised.

Polymorphism

Polymorphism, which translates to “many forms” in Greek, is the capacity of a single interface to be used for a broad class of actions, with the particular action being decided at runtime according to the actual type of the object. “One interface, multiple methods” is a common summary of this idea. Java uses method overloading and overriding mostly to accomplish polymorphism.

Method overloading: As long as the parameter declarations of two or more methods in the same class differ (in terms of number, type, or order of parameters), they can have the same name. When overloading, the return type is not taken into account.

Here’s a Java code example demonstrating method overloading within an OverloadDemo class, followed by its output:

class Calculator {
    // Method to add two integers
    public int add(int a, int b) {
        return a + b;
    }
    // Overloaded method to add three integers
    public int add(int a, int b, int c) {
        return a + b + c;
    }
    // Another overloaded method to add two doubles
    public double add(double a, double b) {
        return a + b;
    }
}
public class Main {
    public static void main(String[] args) {
        Calculator myCalc = new Calculator();
        // Calling the method that adds two integers
        int sum1 = myCalc.add(5, 10);
        System.out.println("Sum of two integers: " + sum1);
        // Calling the method that adds three integers
        int sum2 = myCalc.add(5, 10, 15);
        System.out.println("Sum of three integers: " + sum2);
        // Calling the method that adds two doubles
        double sum3 = myCalc.add(5.5, 10.5);
        System.out.println("Sum of two doubles: " + sum3);
    }
}

Code Output:

Sum of two integers: 15
Sum of three integers: 30
Sum of two doubles: 16.0

As you can observe in the output, the Java compiler accurately selects and executes the appropriate test() method based on the number and data types of the arguments provided during each call. This showcases how method overloading enhances flexibility and clarity by allowing a single, descriptive method name to be used for functionally similar operations on varying data types. The automatic type conversion ensures that even if an exact match isn’t available, a suitable overloaded method can still be invoked through type promotion.

Method Overriding: A subclass method that shares the same return type and signature (name and parameter list) as a method in its superclass is said to be overriding. The subclass’s version is executed when an overridden method is called on a subclass object, thereby “hiding” the superclass’s version. In order to enable dynamic method dispatch, this is decided at run-time.

// Superclass
class Animal {
    // Method in the superclass
    public void makeSound() {
        System.out.println("The animal makes a sound.");
    }
}
// Subclass
class Dog extends Animal {
    // Overriding the makeSound() method
    @Override
    public void makeSound() {
        System.out.println("The dog barks.");
    }
}
public class Main {
    public static void main(String[] args) {
        // Create an object of the Animal class
        Animal myAnimal = new Animal();
        myAnimal.makeSound(); // Calls the method in Animal
        // Create an object of the Dog class
        Dog myDog = new Dog();
        myDog.makeSound(); // Calls the overridden method in Dog
    }
}

Output:

The animal makes a sound.
The dog barks.

Classes: The Blueprint for Objects

In Java, a class is a blueprint or template that specifies an object’s shape and characteristics. Both the code (methods or member methods) that will manipulate the data and the data (instance variables or member variables) that objects of this class will contain are specified. Since a class is a logical abstraction, it doesn’t take up memory until an instance, or object, is made from it.

Class is a keyword used to create classes. Because they group logically related information and encapsulate functionality, they are the basic building blocks of Java programs.

Objects: Instances of a Class

An object is a class’s instance or realisation. The object is the actual “thing” constructed from the blueprint, whereas a class is the blueprint. These values are initialised and memory is allotted for an object’s data when it is instantiated (created).

By creating objects with the new keyword, memory is dynamically allocated and a reference to the newly created object is returned. Because each object of a class has a distinct copy of the instance variables that are defined by its class, modifications to one object’s data do not impact those of another, even if they are of the same type.

Example of Class and Object Creation: Let’s define a simple Book class and then create Book objects.

// Class: Book (the blueprint)
class Book {
    // Instance variables (data)
    String title;
    String author;
    int yearPublished;
    // Constructor (special method to initialize objects)
    public Book(String title, String author, int yearPublished) {
        this.title = title;
        this.author = author;
        this.yearPublished = yearPublished;
    }
    // Method (behaviour)
    public void displayBookInfo() {
        System.out.println("Title: " + title + ", Author: " + author + ", Year: " + yearPublished);
    }
}
public class BookDemo {
    public static void main(String[] args) {
        // Object 1: myBook (an instance of the Book class)
        Book myBook = new Book("The Hitchhiker's Guide to the Galaxy", "Douglas Adams", 1979);
        // Object 2: anotherBook (another instance, separate data)
        Book anotherBook = new Book("1984", "George Orwell", 1949);
        // Call methods on objects
        myBook.displayBookInfo();
        anotherBook.displayBookInfo();
    }
}

Code Output:

Title: The Hitchhiker's Guide to the Galaxy, Author: Douglas Adams, Year: 1979
Title: 1984, Author: George Orwell, Year: 1949

MyBook and anotherBook are separate objects (instances) generated from the Book class, which acts as a blueprint. This example shows how each instance of the Book class contains its own set of data (title, author, yearPublished).

Learning Object-Oriented Programming (OOP) in Java can be easy to grasp at a basic level, but mastering it requires consistent practice. The concepts are logical and build on one another, making the learning curve manageable for most aspiring programmers.

Index