Object-Oriented Programming
Tags: java, programming, codenewbie, webdev
Published: 2024-01-22 14:01:29

## OOP

OOP stands for **Object-Oriented Programming**. It is a programming model that organizes code into objects that are instances of classes, where an object bundles together data and methods, allowing both to operate as one integrated unit.

In Java language, OOP is used to create objects from classes. A Java class acts as a blueprint that defines what data and methods each object will contain. When you create an object from that class, it is called an instance of that particular class.

For example, a `Person` class could be defined by properties like `name`, `age`, and abilities such as `walk()` and `talk()`.

The Person class becomes a template for creating instances of people like John and Mary, which are objects of the template class Person. 

A core difference between OOP and Procedural Programming is the approach to structuring code. Procedural programming focuses on writing procedures or functions that operate on data, whereas OOP emphasizes the organization of code into objects that encapsulate data and behavior.

The key pillars of OOP that support it are **Inheritance**, **Polymorphism**, **Abstraction**, and **Encapsulation**. These core concepts are explored below.


## Inheritance

Inheritance in Java language allows a child class to inherit data and behaviors from a parent class. It enables code reuse by allowing child classes to reuse logic from parent classes.

Inheritance creates hierarchical relationships between classes. Child classes inherit shared parent class logic and can override or extend the inherited capabilities for specific subclass needs.

For example, the `Child` class can inherit from the `Person` class, taking on specific attributes like `name` and `age`, and override some other inherited capabilities like `walk()`.

You can use the `extends` keyword to implement Inheritance in Java. The use of inheritance is realized when the programmer does not wish to define the same set of methods or fields for the new class as an Inheritance links the child and parent classes. The child class inherits and builds on the data & behaviors of the parent.

!\[Inheritance first example\](https://mate-academy-images.s3.eu-central-1.amazonaws.com/inheritance_4b937162da.png)

**Example of Inheritance:**

```java
    class Parent {
    
       // fields
       // methods
      
    }
    
    class Child extends Parent {
    
       // already supports the methods and fields of the `Parent` class
       // additional features
    
    }
```

 **Composition** and **Aggregation** are two types of relationships often confused with **Inheritance**. 


- **Composition** is a "belongs-to" type of relationship. It means that one of the objects is part or member of the other object. Alternatively, we often call it a "HAS-A" relationship (as opposed to an "IS-A" relationship, which is inheritance). These objects' lifecycles are tied. It means that if we destroy the owner object, its member also will be destroyed. For example, the room is destroyed along with the building.


- **Aggregation** is similar to composition. However, it doesn't involve owning. As a result, the lifecycles of the objects aren't tied: everyone can exist independently of each other. For example, take a car and its wheels. We can take off the wheels, and both still exist. 


## Method Overriding

Method overriding allows a subclass to provide a different implementation of a method already defined in its superclass. It allows a subclass to modify the behavior of an inherited method according to its specific requirements.

To override a method, the subclass must declare a method with the same name, return type, and parameter list as the method in the superclass. The overriding method should also be marked with the `@Override` annotation to ensure it correctly overrides a superclass method.

```java
    class Vehicle {
       public void drive() {
           System.out.println("Driving a vehicle...");
       }
    }
    
    class Car extends Vehicle {
       @Override
       public void drive() {
           System.out.println("Driving a car...");
       }
    }
    
    class Bike extends Vehicle {
       @Override
       public void drive() {
           System.out.println("Riding a bike...");
       }
    }
```
The objects of the `Vehicle`, `Car`, and `Bike` classes, when created, can call the `drive()` on each object. The JVM determines the actual type of the object at runtime and executes the corresponding overridden method.

```java
    Driving a vehicle...
    Driving a car...
    Riding a bike...
```
**Please note:** `final`, `static`, and `private` methods cannot be overridden.


## Method Overloading

Method overloading allows multiple methods with the same name but different parameter lists to coexist within a class. It provides a way to define methods that perform similar tasks but with different input parameters.

```java
    class Calculator {
       public int add(int a, int b) {
           return a + b;
       }
    
       public double add(double a, double b) {
           return a + b;
       }
    
       public int add(int a, int b, int c) {
           return a + b + c;
       }
    }
```
The Calculator class can call the `add()` methods with different arguments, as shown above. 

```java
    Calculator calculator = new Calculator();
    
    int sum1 = calculator.add(2, 3); // 5
    double sum2 = calculator.add(2.5, 3.7); 6.2
    int sum3 = calculator.add(2, 3, 4); // 9
```

## Polymorphism

Polymorphism is the ability of objects of different classes to be treated as objects of a common superclass. It allows other objects to respond differently to the same message (method call). Polymorphism enables code flexibility and extensibility by providing a common interface for interacting with objects of different types.

Polymorphism has two types: **Compile-time polymorphism (static binding)** and **Runtime polymorphism (dynamic binding)**. Method overloading is an example of static polymorphism, while method overriding is an example of dynamic polymorphism.

An important example of polymorphism is how a parent class refers to a child class object. Any object that satisfies more than one "IS-A" relationship is polymorphic. For example, let's consider a class `Vehicle` and let `MotorBike` be a subclass of `Vehicle`. So, any `motorBike` **IS** `vehicle`. Here, `MotorBike` satisfies the "IS-A" relationship for its type and superclass `Vehicle.

## Abstraction

Abstraction shows only essential attributes and hides unnecessary information. The primary purpose of abstraction is to hide unnecessary details from the users. Abstraction selects data from a larger pool to show the user. It helps in reducing programming complexity. 

The abstract keyword is a non-access modifier used for classes and methods:

The `abstract` keyword is a non-access modifier used for classes and methods:


- An **abstract class** is a restricted class that cannot be used to create objects (to access it, it must be inherited from another class);
-  An **abstract method** can only be used in an abstract class, and it does not have a body. The subclass provides the body.

Example of abstraction:

(...)

## **Task: Get Drinks**

Let's move on! Let's learn how to implement more complex loops.

One day, the host at a wedding decided to entertain the guests and set a rule: each guest who comes makes a toast, and all guests drink for the health of the newlyweds.

For example:


- First guest arrives — Only one drink is needed;
- Second guest — Two drinks are required;
- Third guest — Three more drinks, and so on.

If 5 guests show up, 15 drinks are required (1 + 2 + 3 + 4 + 5).

If 10, then 55 drinks (1 + 2 + 3 + ... + 10).

Implement the `getDrinks` function that accepts `numberOfGuests` — Find out how many guests will be at the wedding and returns the required number of drinks.

More examples:

```java
    getDrinks(0); // 0 - no guests - no drinks
    getDrinks(2); // 1 + 2 = 3
    getDrinks(6); // 1 + 2 + 3 + 4 + 5 + 6 = 21
```
Check the **Sum of Numbers From 1 to n** theory section to determine how to sum numbers in a loop.


    <details>
     <summary>Hint</summary>
    
     - If the `numberOfGuests === 0` — return `0`.
     - If not, create a variable to count the required portions, for example, `let numberOfPortions = 0`.
     - Create a `for` loop from `1` to `numberOfGuests`.
     - Increase the `numberOfPortions` by the current number of guests at each loop iteration.
     - Return the result after the loop.
    </details>