DEV Community

Cover image for Object Oriented Programming (OOP)
Abhishek Pathak
Abhishek Pathak

Posted on

Object Oriented Programming (OOP)

Object Oriented Programming (OOP)

OOP is a methodology or paradigm to design a program using classes and objects. Its simplifies the software development and mainrenance by providing some conpects below:

Class

Class is a user-defined data type which defines its properties and its functions.

Class is the only logical representation of the data.

For example, Human being is a class. The body parts of a human being are its properties, and the actions performed by the body parts are known as functions.

The class does not occupy any memory space till the time an object is instantiated.

Object

Object is a run-time entity.

It is an instance of the class.

An object can represent a person, place or any other item. An object can operate on both data members and member functions.

In short, Classes are blueprint and object are the actual product which is made using that blueprint

If we take an example, In large factories, they spend millions of dollars to create a blueprint of a car, and that blueprint we can call a class, and using that blueprint, they create millions of cars, and these cars are called objects.

Following is the example of class and object

Code:

class Car {
    String brand = "Tesla";
    int tires;
    String series;
}

public class ClassObject {

    public static void main(String[] args) {
        Car carObj1 = new Car(); // Object 1

        carObj1.series = "A";
        carObj1.tires = 4;

        System.out.println(carObj1.brand + " has " + carObj1.tires + " tires and is of " + carObj1.series +" series");

        Car carObj2 = new Car(); // Object 2

        carObj2.series = "X";
        carObj2.tires = 3;

        System.out.println(carObj2.brand + " has " + carObj2.tires + " tires and is of " + carObj2.series +" series");
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

This approach enhances code reusability and maintains a clear separation of concerns.

Note: When an object is created using a new keyword, then space is allocated for the variable in a heap, and the starting address is stored in the stack memory.

Constructor:

A constructor is a special method that is invoked automatically at the time of object creation. It is generally used to initialise the data members of new objects.

● Constructors have the same name as classes or structures.

● Constructors don’t have a return type. (Not even void.)

● Constructors are only called once, at object creation.

There are three types of constructors.

Non-Parameterized Constructor:

A constructor that has no argument is known as a non-parameterized constructor (or no-argument constructor).

It is invoked at the time of creating an object. If we don’t create one, then it is created by default by Java.

Code:

class Me{

    Me(){
        System.out.println("My name is Abhishek Pathak");
    }
}

public class ClassObject {

    public static void main(String[] args) {

        Me me = new Me();
    }    
}
Enter fullscreen mode Exit fullscreen mode

output:

non parameterized constructor

Parameterized constructor

A constructor that has parameters is called a parameterized constructor.

It is used to provide different values to distinct objects.

Code:


class Car {
    String brand = "Tesla";
    int tires;
    String series;

    Car(int tires, String series) {
        this.tires = tires;
        this.series = series;
    }
}

public class ClassObject {

    public static void main(String[] args) {

        Car carObj1 = new Car(1, "A"); // Object 1

        System.out.println(carObj1.brand + " has " + carObj1.tires + " tires and is of " + carObj1.series +" series");

        Car carObj2 = new Car(3, "X"); // Object 2

        System.out.println(carObj2.brand + " has " + carObj2.tires + " tires and is of " + carObj2.series +" series");
    }
}
Enter fullscreen mode Exit fullscreen mode

output:

‘this’ keyword: ‘this’ keyword in Java refers to the current instance of the class. In OOPS, it is used to:

  1. pass the current object as a parameter to another method

  2. refer to the current class instance variable

Copy Constructor

A copy constructor is an overloaded constructor used to declare and initialise an object from another object.

Code:

class Car {
    String brand = "Tesla";
    int tires;
    String series;

    Car(CarObj obj1) {
        this.tires = obj1.tires;
        this.series = obj1.series;
    }
}
Enter fullscreen mode Exit fullscreen mode

Java has a garbage collector that deallocates memory automatically.

Polymorphism

In simple words, poly means'many’ and morphism means forms.

This means a function can be written in different forms.

Polymorphism allows objects of different classes to be treated as instances of a common superclass.

Now, there are two types of polymorphism:

1. Compile time polymorphism (static).

2. Runtime Polymorphism (Dynamic)

Let’s deep-dive them one by one:

Compile Time Polymorphism

The polymorphism that is implemented at compile time (the compiling stage) is known as compile-time polymorphism. example: Method Overloading

Method Overloading

Method overloading is a technique that allows you to have more than one function with the same name but with different functionality.

The signature of the function is considered here.

What is function signature ?

In Java, a method signature is composed of a name and the number, type, and order of its parameters. Return types and thrown exceptions are not considered to be part of the method signature, nor are the names of parameters; they are ignored by the compiler for checking method uniqueness.

Method overloading can be possible on the following basis:

  1. The type of parameters passed to the function

  2. The number of parameters passed to the function

Code:

class Student {
    String name;
    int roll;

    public void display(String name) {
        System.out.println("Name: " + name);
    }

    public void display(String name, int roll) {
        System.out.println("Name: " + name + " roll: " + roll);
    }
}

public class Polymorphism {

    public static void main(String[] args) {
        Student std = new Student();
        std.display("Abhishek");
        std.display("Abhishek", 20);
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

poly

Runtime Polymorphism

Runtime polymorphism is also known as dynamic polymorphism.

Function overriding is an example of runtime polymorphism.

Function overriding

In a nutshell, function overriding is done when we override the function from the parent class, which means the child class has the same function as the parent class and the child class changes some fields.

This is called dynamic because objects are created in the head, which are dynamic. You will understand more when we do the inheritance.

Code:

Will do after Inheritance

Now, the next one on our list is THE GREAT Inheritance

Inhertance

Inheritance is a process in which one object acquires all the properties and behaviours of its parent object automatically.

In such a way, you can reuse, extend, or modify the attributes and behaviours that are defined in other classes.

In Java, the class that inherits the members of another class is called the derived class, and the class whose members are inherited is called the base class.

The derived class is the specialised class for the base class.

We have different types of inheritance:

  1. Single Inheritance

  2. Hierarchical Inheritance

  3. Multilevel Inheritance

Let's dive into them one by one:

1. Single Inheritance

In Java, we achieve inheritance using the extends keyword.

When one class inherits another class, it is known as single-level inheritance.

class Brand {

    int tires = 4;
    public void name() {
        System.out.println("This is class brand");
    }
}

class Tesla extends Brand {
    public void name(String name) {
        System.out.println("The brand is: "+ name + " with " + this.tires +" tires");
    }
}

public class Inheritance1 {

    public static void main(String[] args) {
        Tesla t = new Tesla();
        t.name("Tesla");
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, we can observe that the class Tesla extends Brand class and class Tesla make use of variable tyres.

Until now, you may have observed that both the function name in the parent class, i.e., base class, name is used in the child class, i.e., derived class. This is called Run-Time Polyorphism.

Hierarchical inheritance:

Hierarchical inheritance is defined as the process of deriving more than one class from a base class.

class Pencil {
    int size = 2;
}

class Apsara extends Pencil{
    Apsara(){
        System.out.println("This is Apsara with pencil length" + this.size);
    }
}

class Doms extends Pencil {
    Doms(){
        System.out.println("This is Doms with pencil length" + this.size);
    }
}
Enter fullscreen mode Exit fullscreen mode

Multilevel inheritance:

Multilevel inheritance is the process of deriving a class from another derived class.

class Brand {

    int tires = 4;
}

class Manufacturer extends Brand{
    String mname = "Tesla";
}

class Tesla extends Manufacturer {
    public void name(String name) {
        System.out.println("The brand is: "+ name + " with " + this.tires +" tires and manu by " + this.mname );
    }
}

public class Inheritance1 {

    public static void main(String[] args) {
        Tesla t = new Tesla();
        t.name("Tesla");
    }
}
Enter fullscreen mode Exit fullscreen mode

output:

multi-level

Hybrid inheritance

Hybrid inheritance is a combination of simple, multiple inheritance and hierarchical inheritance.

Now, we will move forward with encapsulation.

Encapsulation

Encapsulation is the process of combining data and functions into a single unit called a class. In encapsulation, the data is not accessed directly; it is accessed through the functions present inside the class.

In simpler words, attributes of the class are kept private and public; getter and setter methods are provided to manipulate these attributes.

Encapsulation helps us achieve data hiding.

Data hiding:

Data hiding is a language feature to restrict access to members of an object, reducing the negative effect of dependencies. e.g., the "protected" and "private" features in Java

Before moving with encapsulation, we need to have some knowledge of access modifiers.

Access Modifiers

Access modifiers are keywords that determine the visibility or accessibility of classes, methods, fields, and constructors within a programme.

They control which parts of the code can be accessed from different classes or packages.

  1. Public
  2. Protected
  3. Default
  4. Private

Let's do a deep dive into each of these.

1. Public

The public access modifier allows a class, method, field, or constructor to be accessible from anywhere in the programme, even from other classes and packages.

public class Car {
    public String brand = "Tesla";
    public void startEngine() {
        System.out.println("Engine started.");
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Protected:

The protected access modifier allows a class, method, or field to be accessible within its own package and by subclasses in other packages.

protected class Vehicle {
    protected String type = "Automobile";
    protected void honk() {
        System.out.println("Honk honk!");
    }
}
Enter fullscreen mode Exit fullscreen mode

3. default (no modifier)

If no access modifier is specified, it's considered as the default access level. A class, method, or field with default access can be accessed only within its own package.

class Animal {
    String name = "Unknown";
    void makeSound() {
        System.out.println("Some sound");
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Private

The private access modifier restricts the visibility of a class member to only within the same class. It's the most restrictive access level.

class BankAccount {
    private double balance = 0.0;
    private void deductFees() {
        balance -= 10.0;
    }
}
Enter fullscreen mode Exit fullscreen mode

This much is enough for the access modifiers, and we will head back to our encapsulation.

So, encapsulation makes use of access modifiers to achieve data hiding.

As mentioned above, encapsulation makes use of getters and setters to access the attributes.

You will understand more with the following example:

class Bank {
    private double balance = 0.0;

    public Bank(double initial) {
        balance = initial;
    }

    public double getBalance() {
        return balance;
    }

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("Deposited: " + amount);
        }
    }

    public void withdraw(double amount) {
        balance -= amount;
        System.out.println("Widrawl Done");
    }
}

public class Encapsulation {
    public static void main(String[] args) {
        Bank bank = new Bank(10);

        System.out.println("Initial Balance: " + bank.getBalance());
        bank.deposit(30);
        bank.withdraw(3);
        System.out.println("Balance after widrawl: " + bank.getBalance());
    }
}
Enter fullscreen mode Exit fullscreen mode

This example shows the perfect encapsulation. The attribute balance is made private, so only the class methods can use and manipulate it.
Try playing around with it.

Now, next we have Abstraction

Abstraction

This time, I will be using a simple example, sure

Imagine driving a car.

You don't need to know every intricate detail of how the engine works; you just need to understand the basic functions such as accelerating, braking, and steering.

Abstraction works similarly in software development.

It enables you to create simplified models of real-world objects, emphasising what's important while concealing the complexities.

Here, we try to achieve an abstract view.

Wasn't this a simple one?

In simple terms, it is hiding unnecessary details and showing only the essential parts and functionalities to the user.

Data binding

Data binding is the process of binding the application UI and business logic. Any change made in the business logic will reflect directly on the application UI.

Abstraction is achieved in two ways:

  1. Abstract class
  2. Interfaces (Pure Abstraction)

Let's do a deep dive into each of them.

1. Abstract Class

In Java, abstraction can be achieved using the abstract class.

Following are the points that will give some glimmer:

  • An abstract class must be declared with an abstract keyword.
  • It can have abstract and non-abstract methods.
  • It cannot be instantiated.
  • It can have constructors and static methods as well.
  • It can have final methods that will force the subclass not to change the body of the method.
abstract class Shape {
    abstract void draw();
    Shape(){
        System.out.println("Creating new shape");
    }
}

class Circle extends Shape {
    void draw() {
        System.out.println("I'm drawing Circle here");
    }
}

class Square extends Shape {
    void draw() {
        System.out.println("I'm drawing Square here");
    }
}

Enter fullscreen mode Exit fullscreen mode

Here, as you can see, we are using the draw method again and again in the derived classes.

2. Interfaces (Pure Abstraction)

This is another way to achieve abstraction.

Some of the specifications are:

  • All the fields in interfaces are public, static, and final by default.

  • All methods are public and abstract by default.

  • A class that implements an interface must implement all the methods declared in the interface.

interface Shape {
    double calculateArea();
    double calculatePerimeter();
}

class Circle implements Shape {
    double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double calculateArea() {
        return Math.PI * radius * radius;
    }

    public double calculatePerimeter() {
        return 2 * Math.PI * radius;
    }
}
Enter fullscreen mode Exit fullscreen mode

Interfaces support the functionality of multiple inheritance

This much is enough as per the basic requirement, if you want to deep dive, you must use googulu(google)


I will be adding more to it, based on the comments


If the article helps you, leave a like, follow, or anything 🙂.

You can follow me on LinkedIn, GitHub, Dev.to and hashnode.

Bye

Top comments (2)

Collapse
 
vanessatelles profile image
Vanessa Telles • Edited

For some reason is easier to explain OOP concepts using car-related topics, I do that with interns all the time 😆

I saved your post and will forward it to the juniors on my team 👍

Collapse
 
scorcism profile image
Abhishek Pathak

hey thank you for the awesome comment. Car example is supreme lol. Thank you for your time buddy.