Java OOPs – Mastering Object Oriented Programming

Before understanding the OOPs(Object Oriented Programming) concept in Java, let’s first understand what the procedural programming paradigm is.  

Procedural programming is like following a set of instructions to solve a problem. It’s similar to using a recipe to cook a meal. Each step in the recipe represents a specific action you need to take, and when you complete all the steps, you have a delicious dish.

In procedural programming, you organize your code into smaller tasks or functions that perform specific actions. It’s like breaking down the cooking process into chopping, seasoning, and stirring. Each function focuses on doing one thing well. While this approach works fine for simple programs, it can become tricky to handle as your program becomes larger and more complex. Imagine if your recipe had hundreds of steps, and you had to keep track of all of them. It would be challenging to manage and make changes without making mistakes.

This is where Object-Oriented Programming (OOP) steps in. It offers a better way to manage and organize code. OOPs (Object-Oriented Programming) in Java is a way of writing code that mimics how things work in the real world. It focuses on creating objects that have properties and behaviors, just like things we encounter every day.

Imagine you have a pet dog named Max. Max has his own unique characteristics like breed, color, and age. He can also perform certain actions like barking, eating, and playing. Max is an object, and all these characteristics and actions define him. In Java, objects are the core building blocks of the program, just like Max is the core element in our analogy.

By using OOPs in Java, we can organize our code more efficiently, make it easier to understand and maintain and build complex systems by representing real-life entities and their interactions. So, in simple terms, OOPs in Java is about creating objects that resemble real-life things, giving them characteristics and actions, and using them to build powerful and flexible programs.

Object Oriented Programming

We already saw the benefits that come with Object Oriented Programming, but let’s again have a view on its need.

Need for Object-Oriented Programming:-

Key needs for using Object-Oriented Programming are:-

  1. Organization: OOP helps keep our code organized by breaking it down into smaller, manageable pieces.
  2. Reusability: OOP allows us to reuse code that has already been written. 
  3. Simplicity: OOP makes complex problems easier to understand by representing them as objects. 
  4. Flexibility: OOP lets us make changes to our code without affecting other parts. 
  5. Collaboration: OOP enables different developers to work on different parts of a project independently and then put them together. 
Need for Object-Oriented Programming

Now you must be wondering what are objects and classes, why is it named as object-oriented programming. But let’s first understand what classes and objects are.

What Is A Class In Object Oriented Programming (OOPs)?

Consider that you are a car enthusiast who wants to create various cars of different types.  A class is like a blueprint or a set of instructions that helps you create those cars.

Think of the class as a guide that tells you what each car should look like and what it can do. It specifies things like the car’s color, model, and how fast it can go. It also lists the actions the car can perform, such as accelerating, braking, and turning. Now, when you want to make a specific car, like a sports car, you follow the instructions in the class. You choose the color, model, and speed for your sports car. This specific car you create is an instance of the class.

In simpler terms, a class is like a blueprint that guides you in building different cars. Each car you build using that blueprint is an instance of the class. You can create multiple cars based on the same blueprint, but each car can have its own unique characteristics. You may organize and build items more quickly by using classes. By giving you a consistent set of instructions for making comparable items, it saves you time. It also makes it simpler to manage and modify your cars in the future because you may alter the blueprint (class) without affecting the cars you’ve already made.

For the above example, we can define attributes (also known as properties) and Java methods.

Attributes (Properties) of the Car class:

  • Color: Represents the color of the car (e.g., red, blue, silver).
  • Model: Represents the model or make of the car (e.g., Ferrari, Honda, Toyota).
  • Horsepower: Represents the power of the car’s engine (e.g., 500, 200, 150).

Methods of the Car class:

  • Accelerate(): Represents the action of accelerating the car.
  • Brake(): Represents the action of applying the brakes to the car.
  • Turn(): Represents the action of turning the car.
  • SetColor(): Helps to set the color of the car.
  • SetHorsePower(): Helps to select the Horsepower for the car.

Syntax:

public class Car {
    // Attributes
    // Methods
    // Additional methods or constructors can be defined here
}
Class In Object Oriented Programming

Before going forward, let’s discuss some terms you need to know.

  1. Member Functions – Member functions (methods) define what an object can do or what functions an object can perform. Member functions represent actions, like “Accelerate()” and “Break()” for the above example.
  1. Instance Variables – Instance variables (properties) store an object’s specific information or state. These variables hold data, like “color” or “model” for a car.

What Is An Object In Object Oriented Programming(OOPs)?

Consider an object to be a particular car that you designed using the class as your model. It has a special set of attributes and actions of its own. For example, you may have a red, Ferrari-branded sports car item with a powerful engine. Just like how you can build multiple cars using the same blueprint, you can create multiple objects based on the same class. Each object will have its own distinct features. You could create another object representing a sedan with a blue color, a Honda model, and a fuel-efficient engine.

Objects in OOP allow us to bring our classes to life. They represent the actual things we want to work with and manipulate in our programs. We can perform actions on these objects, such as accelerating the sports car or applying brakes to the sedan. By using objects, we can organize and manage our code more effectively. We can treat each object as an individual entity, working with them separately or together as needed. Objects help us create modular and reusable code, making our programs more flexible and easier to understand.

Here’s the syntax for creating an object of the Car class:

public class Main {
    public static void main(String[] args) {
        // Creating an object of the Car class
        Car myCar = new Car();
       
        // Accessing and modifying the attributes of the car
        myCar.color = "Red";
        myCar.model = "Ferrari";
        myCar.horsepower = 500;
       
        // Calling the methods of the car
        myCar.accelerate();
        myCar.brake();
        myCar.turn();
    }
}

In the above syntax, we first create a class named Main and define the main method. Inside the main method, we create an object of the Car class using the new keyword and assign it to the variable myCar.

We can then access and modify the attributes of the car object using the dot notation (myCar.color, myCar.model, myCar.horsepower). For example, we set the color to “Red”, model to “Ferrari”, and horsepower to 500. Finally, we can call the methods of the car object using the dot notation as well (myCar.accelerate(), myCar.brake(), myCar.turn()). These method calls perform the respective actions on the car object.

Object In Object Oriented Programming

Object-Oriented Programming (OOPs) in Java is built upon four fundamental concepts that serve as the pillars of organizing and structuring code to create efficient and reusable programs.

Four Pillars Of OOPs In Java

The following are the basic principles of OOP in Java. They are known as the principles as the entire OOP lays its foundation on these principles.

  • Encapsulation
  • Inheritance
  • Polymorphism
  • Abstraction

Let’s deep dive into the depth of every pillar of Object-Oriented Programming and have a clear understanding of how things work. Image a scenario of a school with students and teachers. Let’s understand all four pillars with the help of this real-life scenario.

Four Pillars Of OOPs In Java Object Oriented Programming

Pillar 1. Encapsulation

Imagine a school where teachers and students are divided into various departments. Each department is responsible for carrying out its particular set of duties. In OOPs, encapsulation is like creating separate departments in the school. It allows us to group related data and functions together into classes, and hide the internal details from other classes. For instance, the Student class may include details about the student’s name, age, and grades, while the Teacher class could include details about the teacher’s name, subject, and experience. This keeps them separate and organized while allowing each class to maintain its own data and behavior.

  • In encapsulation, data in the class is hidden from other functions and classes. The data is inaccessible by other classes and can be accessed only by that class in which it is declared. Hence, it is also known as ‘Data Hiding’. 
  • In Java, class forms the basis of encapsulation.

Example

public class Student {
    private String name;
    private int age;
    private double[] grades;
}

In this illustration, the Student class contains data about a student, including their name, age, and grades. The properties (name, age, and grades) are marked as private, so only members of the class can access them. 

Pillar 2. Inheritance

In a school, there are different levels of hierarchy among teachers. For example, there are subject teachers, department heads, and principals. In OOPs, inheritance allows us to create a hierarchy of classes where a class can inherit properties and behaviors from a parent class. For example, we can have a base class called Teacher, and derived classes like SubjectTeacher, DepartmentHead, and Principal that inherit common attributes and methods from the Teacher class. This way, we can reuse and extend the functionality of the base class, making the code more organized and reducing redundancy. 

Effective code organization and reuse are made possible through inheritance. It enables you to build a hierarchy of classes, with the derived classes inheriting and extending the base class’s common features and behaviors. By avoiding code duplication, you can increase the effectiveness and maintainability of your program.

Example

// Teacher class
class Teacher {
  protected String name;
  public void setName(String name) {
        this.name = name;
  }
  public void displayInfo() {
      System.out.println("Name: " + name);
  }
}

// SubjectTeacher class inheriting from Teacher
class SubjectTeacher extends Teacher {
  protected String Subject;
  public void setSubject(String sub) {
        Subject = sub;
  }
  public void displayInfo() {
        super.displayInfo();
        System.out.println("Subject: " + Subject);
  }
}

// DepartmentHead class inheriting from Teacher
class DepartmentHead entends Teacher {
  protected String Department;
  public void setDepartment(String dep) {
        Department = dep;
  }
  public void displayInfo() {
        super.displayInfo();
        System.out.println("Department: " + Department);
  }
}

public class Main {
      public static void main (String[] args) {
  SubjectTeacher st = new SubjectTeacher();
st.setName("Alok");
st.setSubject("Programming in Java");
st.displayInfo();
DepartmentHead dh = new DepartmentHead();
dh.setName("Rishi");
dh.setDepartment("Accounts");
dh.displayInfo();
      }
}

Output:

Name: Alok
Subject: Programming in Java
Name: Rishi
Department: Accounts

In this example, Teacher class is the parent class, and the SubjectTeacher and DepartmentHead classes are child classes that inherit from the Teacher class using extends keywords. The child classes inherit the name attribute and the setName() and displayInfo() methods from the parent class. The SubjectTeacher class has an additional attribute called Subject, and it overrides the displayInfo() method to display the Subject as well. Similarly, the DepartmentHead class has an additional attribute called Department and it overrides the displayInfo() method to display department as well. 

In the Main class, we create objects of the SubjectTeacher and DepartmentHead classes and use the inherited attributes and methods. The displayInfo() method of each class is called, which shows the information specific to that class along with the common information inherited from the Teacher class.

Inheritance in Java can be categorized into different types based on how classes inherit from each other. Here are the commonly used types of inheritance:

  1. Single Inheritance:

Single inheritance occurs when a class inherits from only one parent class. In other words, a child class extends a single parent class. It represents an “is-a” relationship between classes. For example, a Car class can inherit from a Vehicle class.

Syntax:

class Parent {
    // Parent class members
}

class Child extends Parent {
    // Child class members
}
Single Inheritance in Java Object Oriented Programming
  1. Multiple Inheritance (Not supported in Java):

A class that has several inheritances from different parent classes is said to have multiple inheritance. A class cannot directly inherit from numerous classes in Java since it does not support multiple inheritance for classes. This restriction is put in place to prevent difficulties and disputes that can occur while resolving methods and attribute conflicts from several parents.

Syntax:

// Java does not directly support multiple inheritance for classes
Multiple Inheritance in Java Object Oriented Programming
  1. Multilevel Inheritance: 

When a class derives from a different child class, a chain of inheritance is formed. This implies that one class becomes the parent of another, which in turn becomes the parent of a third class. For instance, a Cuboid class may inherit from a Rectangle class, which itself inherits from a class called Shape.

Syntax:

class Grandparent {
    // Grandparent class members
}

class Parent extends Grandparent {
    // Parent class members
}

class Child extends Parent {
    // Child class members
}
  1. Hierarchical Inheritance:

Multiple classes can derive from a single parent class through a process known as hierarchy of inheritance. It illustrates an inheritance tree in which one parent class has several children. A class called Animal, for example, might include subclasses called Dog, Cat, and Bird.

Syntax:

class Parent {
    // Parent class members
}

class Child1 extends Parent {
    // Child1 class members
}

class Child2 extends Parent {
    // Child2 class members
}

class Child3 extends Parent {
    // Child3 class members
}
Hierarchical Inheritance in Java Object Oriented Programming
  1. Hybrid Inheritance (Combination of the above types):

A hybrid inheritance is one that combines two or more of the aforementioned inheritance categories. Complex class hierarchies are made by combining various methods of inheritance. Java, on the other hand, only permits a single class inheritance and multiple interface inheritance, avoiding the diamond problem (ambiguity resulting from multiple inheritance).

Syntax:

class Grandparent {
    // Grandparent class members
}

class Parent extends Grandparent {
    // Parent class members
}

class Child1 extends Parent {
    // Child1 class members
}

class Child2 extends Parent {
    // Child2 class members
}
Hybrid Inheritance in Java Object Oriented Programming

It’s important to note that Java supports single inheritance for classes, but it allows multiple inheritance for interfaces through interface implementation. This allows classes to inherit from multiple interfaces, enabling them to define multiple behaviors.

Pillar 3. Polymorphism

In a school, teachers have different teaching styles based on the subjects they teach. Polymorphism in OOPs allows for diverse behaviors by treating objects of different classes as objects of the same parent class. This means that even though they belong to the same category, each teacher can have their own unique way of teaching. It adds flexibility and adaptability to the code, making it more dynamic.

Example:

// Parent Class
class Teacher {
    public void teach() {
        System.out.println("This is a teacher.");
    }
}

//MathTeacher class entends from Teacher class
class MathTeacher extends Teacher {
    public void teach() {
        System.out.println("This is a math teacher.");
    }
}

// EnglishTeacher class extends from Teacher class
class EnglishTeacher extends Teacher {
    public void teach() {
        System.out.println("This is an English teacher.");
    }
}

public class Main {
    public static void main(String[] args) {
        Teacher teacher1 = new MathTeacher();
        Teacher teacher2 = new EnglishTeacher();

        teacher1.teach();
        teacher2.teach();
    }
}

Output:

This is a math Teacher.
This is an English Teacher.

The Teacher class is the parent class in this case, while the MathTeacher and EnglishTeacher classes are the kid classes. Each child class overrides the parent class’s teach() method to offer its own implementation. The main method shows polymorphism by producing objects from several child classes but treating them as objects from the parent class. When you call the teach() method on an object, the implementation that is appropriate for the object type is executed.

Example of Polymorphism in java Object Oriented Programming

Polymorphism in Java can be categorized into two types: 

  • Compile-Time Polymorphism (Method Overloading) 
  • Runtime Polymorphism (Method Overriding).
  1. Compile-time Polymorphism (Method Overloading):
  • Method overloading allows us to have multiple methods with the same name but different parameters. 
  • The compiler decides which method to execute based on the number, types, and order of the arguments passed.

Example:

class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
   
    public int add(int a, int b, int c) {
        return a + b + c;
    }
}

public class Main {
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        int result1 = calc.add(2, 3);
        System.out.println("Sum is: " + result1);
        int result2 = calc.add(2, 3, 4);
        System.out.println("Sum is: " + result2);
    }
}

Output:

Sum is: 5
Sum is: 9

Explanation:

  • In this example, we have a Calculator class with two add() methods. One method takes two integers as arguments, and the other method takes three integers.
  • We create an instance of the Calculator class and invoke the add method with two integers and three integers. The output shows the sum of the numbers.
  1. Runtime Polymorphism (Method Overriding):
  • Method overriding occurs when a subclass provides its own implementation of a method that is already defined in its parent class. 
  • The method in the subclass must have the same name, return type, and parameters as the method in the parent class.
  • The decision of which method to execute is made at runtime based on the actual object type.

Example:

class Animal {
    public void makeSound() {
        System.out.println("The animal makes a sound.");
    }
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("The dog barks.");
    }
}

class Cat extends Animal {
    public void makeSound() {
        System.out.println("The cat meows.");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();
       
        animal1.makeSound();
        animal2.makeSound();
    }
}

Output:

The dog barks.
The cat meows.

Explanation:

  • Here, we have an Animal class with a makeSound method. Two subclasses, Dog and Cat, override the makeSound method.
  • We create instances of Dog and Cat and invoke the makeSound method. The output displays the specific sound made by each animal.

These examples demonstrate how polymorphism allows different objects to behave differently based on their types, providing flexibility and dynamic behavior in Java programs.

Pillar 4. Abstraction

Abstraction in OOPs is like focusing on the important parts while ignoring the complex details. It’s similar to how students interact with teachers without knowing the inner workings of the school. In Java, we can create abstract classes or interfaces that act as blueprints for other classes. These abstract classes define the common structure and behavior that other classes should follow. Abstraction helps us separate the important features from the implementation details, making the code more organized, easier to understand, and maintain. 

Example:

abstract class Teacher {
    String name;
    int age;

    abstract void teach();
}

class MathTeacher extends Teacher {
    @Override
    void teach() {
        System.out.println("The math teacher is explaining algebraic equations.");
    }
}

class EnglishTeacher extends Teacher {
    @Override
    void teach() {
        System.out.println("The English teacher is discussing literature analysis.");
    }
}

public class School {
    public static void main(String[] args) {
        Teacher mathTeacher = new MathTeacher();
        mathTeacher.teach();

        Teacher englishTeacher = new EnglishTeacher();
        englishTeacher.teach();
    }
}

Output:

The math teacher is explaining algebraic equations.
The English teacher is discussing literature analysis.

In this example, the Teacher class is an abstract class that defines the common attributes (name and age) and the abstract method teach(). The MathTeacher and EnglishTeacher classes are derived from the Teacher class and provide their own implementation of the teach() method. The School class demonstrates how different types of teachers can be treated as objects of the same parent class (Teacher), allowing for abstraction and polymorphism.

Other Concepts Of Object Oriented Programming Are-

We have discussed all 4 major pillars (concepts) of object-oriented programming. Now we will be discussing other concepts of OOPs that play a crucial role in Java programming.

  1. Coupling:-

Coupling is like the level of connection between classes or parts of a system. It shows how closely they rely on each other. It measures how closely one class is connected to another. Coupling is of two types:

  • Loose Coupling: Classes have minimal dependency on each other, allowing for flexibility and easy maintenance. Changes in one class have minimal impact on other classes.
  • Tight Coupling: Classes have a strong dependency on each other, making it difficult to modify or extend the system. Changes in one class may require modifications in multiple classes.

For example, imagine a car and a garage. If the car is tightly coupled with the garage, it can only be parked in that specific garage. However, if the car is loosely coupled, it can be parked in any suitable garage.

Loose Coupling  and Tight Couplings in Object Oriented Programming
  1. Cohesion:-

Cohesion measures how strongly the elements within a class or module are related to each other. It represents the degree to which a class focuses on a single, well-defined purpose. Cohesion is of two types:

  • Low Cohesion: When a class or module has multiple unrelated tasks, it exhibits low cohesion. It does too many things, making the code harder to understand and maintain.
  • High Cohesion: When a class or module has a single, well-defined task, it demonstrates high cohesion. It focuses on a specific responsibility, leading to cleaner and more maintainable code.

In summary, high cohesion is good because it keeps related code together and makes it easier to work with. Low cohesion, on the other hand, can make code more complex and harder to manage.

Low Cohesion and High Cohesion in Object Oriented Programming
  1. Association:-

In OOPs, association refers to the relationship between two classes or objects. It depicts how objects interact with one another. Associations are classified into four types: one-to-one, one-to-many, many-to-one, and many-to-many.

  • One-to-One Association: Consider a person and their passport. A person can only have one passport, and each passport belongs to a single individual. This is an example of a one-to-one relationship.
  • One-to-Many Association: Consider a university and its students as an example of a one-to-many relationship. A university can have many students, but each student can only be affiliated with one institution. This is an example of a one-to-many relationship.
  • Many-to-One Association: Think of a customer and their orders at an online store. A customer can place multiple orders, but each order belongs to only one customer. This is an example of a many-to-one association.
  • Many-to-Many Association: Consider a social media platform where users can follow other users. A user can have multiple followers, and a follower can follow multiple users. This is an example of a many-to-many association.

In each type of association, objects or classes are connected in a specific way, enabling them to work together and exchange information. Associations allow us to model real-world relationships in our code, making it more meaningful and powerful.

Association
  1. Aggregation:-
  • Aggregation is a way to achieve Association. 
  • Aggregation in OOPs represents a “has-a” relationship, where one class contains or is composed of other classes. 
  • It allows us to represent complex relationships and hierarchies in a modular and organized way. 
  • For example, a library can have multiple books, but both can exist independently.
  1. Composition:-
  • Composition in object-oriented programming is a stronger form of aggregation. 
  • It represents a “whole-part” relationship where the parts cannot exist without the whole. 
  • In other words, the lifetime of the contained objects is controlled by the container object.

Let’s take an example of a House. A house is composed of various components such as rooms, doors, and windows. The House class represents the whole, while the Room, Door, and Window classes represent the parts. The parts are created and destroyed along with the house.

Example:

class House {
  private Room livingRoom;
  private Room bedroom;
  private Door mainDoor;
  private Window[] windows;

  // Constructor
  public House() {
      livingRoom = new Room();
      bedroom = new Room();
      mainDoor = new Door();
      windows = new Window[4];
      for (int i = 0; i < windows.length; i++) {
        windows[i] = new Window();
      }
  }
 
  // Other methods and functionalities...
}

In this example, the House class encapsulates the rooms, doors, and windows. When a new House object is created, it automatically creates the associated rooms, doors, and windows. If the House object is destroyed, all its parts (rooms, doors, and windows) are also destroyed.

What Are the Advantages of Object-Oriented Programming (OOPs) in Java?

The benefits of OOPs in Java are

  1. Modularity: OOPs breaks code into smaller, self-contained modules (objects) for easier understanding and maintenance.
  2. Encapsulation: OOPs protects data and provide a clear interface for interacting with objects.
  3. Code organization: OOPs organize code through classes and inheritance, reducing duplication and promoting reuse.
  4. Code maintenance: OOPs allow for easier debugging, fixing issues, and adding new features without impacting the entire codebase.
  5. Flexibility and extensibility: OOPs enables easy addition of new classes and objects without modifying existing code.
  6. Abstraction and polymorphism: OOPs simplify code by focusing on essential features and allow objects to behave differently based on the context.

By leveraging these benefits, OOPs in Java enables developers to create well-organized, maintainable, and scalable code, promoting code reusability and efficient software development.

Conclusion

  • Object-oriented programming (OOP) in Java is a programming paradigm that revolves around the concepts of classes and objects.
  • A class in Java is a blueprint that defines the properties (attributes) and behaviors (methods) that objects of that class will have.
  • Objects are instances of classes, representing real-world entities with their own states and behaviors.
  • Inheritance allows classes to inherit properties and behaviors from other classes, promoting code reuse and establishing hierarchical relationships.
  • Polymorphism enables objects to take on different forms, allowing flexibility and the ability to handle objects of different types through a common interface.
  • Encapsulation is the concept of bundling data and methods together within a class, protecting data from external access, and ensuring controlled access through methods.
  • Abstraction allows developers to focus on essential features of an object, hiding unnecessary implementation details and making code more manageable.
  • Coupling refers to the degree of dependency between classes, with low coupling being desirable for modular and flexible systems.
  • Cohesion refers to the degree of relatedness of the members within a class, with high cohesion indicating a well-defined and focused class.
  • Aggregation represents a relationship where one class has a reference to another class, indicating a “has-a” relationship.
  • Association represents a relationship between classes, indicating that objects of one class are connected to objects of another class.
  • Composition is a stronger form of aggregation, where the composed object cannot exist without the owner object.
  • Object-oriented programming in Java promotes modularity, reusability, and code organization, leading to more maintainable and scalable software applications.

Leave a Reply

Your email address will not be published. Required fields are marked *