What the heck is OOP? Let me help you understand it! (with detailed Java code examples)17 min read

Have you ever heard about OOP? I dare you did. With your curiosity, perhaps you already visited Wikipedia and some other places to learn about this concept, but in the end, you just superficially understand OOP stands for object-oriented programming and it is a programming paradigm based around “object” and contains attributes and properties. I think the best way to help you get the concepts is by giving examples, so in this article, I will help you better understand what is OOP and its related concepts with Java code examples.

When talking about OOP we usually talk about the languages that support this programming paradigm, one of the most prevalent examples is Java programming language. OOP as I mentioned before, stands for Object-oriented programming based on the concept of “objects” which can contain data and fields (often known as attributes and properties).

In general, Object-oriented programming is a kind of way of building software based on real-world entities using classes and objects. Object-oriented programming is an approach to designing modular reusable software systems.

What is a class?

In OOP and in Java more specifically, a class is a template or blueprint that provides initial value, methods, and behaviors for creating new objects.

As a picture above, there is a class named Dog which serves as a blueprint to creating new Dog objects and those objects will have some features such as numOfLegs, numOfTail, bark, and wagginTail. Let’s sketch this Dog class in Java:

public class Dog {
    // states
    int numOfLegs = 4;
    int numOfTail = 1;
    
    // create an empty constructor
    Dog() {}

    // behaviors 
    void bark() {
        System.out.println("Woof!");
    }
    void waggingTail() {
        System.out.println("I am wagging my tail!");
    }
}

On the fragment code above, we can observe that class in Java has several components some others, which are:

  • Class name: The name of the class, it should begin a capital letter.
  • Modifier: Class in Java can either marked public or default.
  • Superclass: A class can have a parent class by using keyword extends, it’s considered one of the core principles of OOP in Java which we will discuss right later on.
  • Interface: Class can also implement an interface by using keyword implements.
  • Body: The actual code for our class, which surrounded by the curly braces { }.

In order to create a new object from a class in Java, we need to create a constructor in our class. The number of constructors in a class is not limited by one and you can create many constructors as you want. The role of the constructor is, when you create an object (an object created by a class is called an instance), this instance will look at the right constructor in the class and call this constructor for creating a new object. The role of a constructor is important because it prepares new objects for use. We cannot create a new object if there is no constructor, but usually, even when you forget to create a constructor, Java usually does it for you by creating an empty constructor.

What is an object?

Now we already know a class is a kind of blueprint to create a new object, so what is an object? An object is an instance of a class that has an identity, state, and behavior. An object in OOP is nothing but real-world entities such as a dog, a cat, a car, etc…Consider the Dog example:

IdentitydogId, etc…
StatenumOfLegs, numOfTail, etc…
Behaviorbark(), waggingTail(), etc…
  • Identity: one class can create many objects, identity makes an object unique when compared with other objects.
  • State: this is what objects have, dog can have numOfLegs, numOfTail, etc…
  • Behavior: the actions of an object, what object does such as bark, waggingTail.

Now let’s create a dog class with the given class by adding some extra code:

public class Dog {
    // states
    int numOfLegs = 4;
    int numOfTail = 1;
    // create an empty constructor
    Dog() {}

    // behaviors 
    void bark() {
        System.out.println("Woof!");
    }
    void waggingTail() {
        System.out.println("I am wagging my tail!");
    }

    public static void main(String[] args){
        // create a new Dog object by a new keyword, it will call the constructor of this class.
        Dog a = new Dog(); 
        // get the number of legs 
        System.out.println(a.numOfLegs);
        // get the number of tail 
        System.out.println(a.numOfTail);
        // call the method bark
        a.bark();
        // call the method waggingTail
        a.waggingTail();
    }
}

Output:

4
1
Woof!
I am wagging my tail!

We have created an object based on the Dog class, because the object we created is an instance of this class, then it has all attributes of this class including access to the variables (states), methods (behaviors) and its constructor. So what is a method? A method is a collection of statements that perform some specific task. As in the example above, we have defined two methods bark() and waggingTail(). Methods can perform some specific tasks without returning anything and methods help us reuse the code without retyping.

From now, we understand some crucial concepts of OOP such as class, object, and method. Then what’s next? What we have next to consolidate our understanding of OOP is the 4 core concepts: Abstraction, Encapsulation, Inheritance, and Polyphomism.

What is Abstraction?

Abstraction is a property providing essential information for the users and hiding the background details, the non-essential units are not displayed for the user. For example, you open your browser and login into your Facebook account, the webserver hides data it processes to check your account and you just have to wait for a moment. Or a smartphone, the producers try to bring you a phone to use as easy as possible, they hide the complex details and display just what you need.

Abstraction may also be defined as the process of identifying different objects in the same group. For example in the real world, we have cars and trucks belong to the same group Vehicle because they have some things in common such as gearboxes, engines, tires, breaks, etc…But cars and trucks have different engine types and different types of shapes.

Abstraction example

Abstraction in Java

In Java, we can achieve abstraction by either Interface or Abstract classes, we can achieve 100% abstraction by using Interface in Java.

What is an abstract class?

In Java, a class declared with an abstract keyword is considered an abstract class, the abstract class can contain abstract methods and non-abstract methods, it needs to be extended and implemented. An abstract class can have a constructor but it cannot be instantiated. With abstract class, we can achieve abstraction from 0% to 100%.

  • An abstract class starts with an abstract keyword.
  • An abstract class can have abstract methods, i.g methods declared without implementation and the implementation leaves for the subclass or concrete methods that have their own body.
  • An abstract method needs to be defined in an abstract class, but an abstract class can have both concrete and abstract methods.
  • You can’t create a new object from an abstract class, the details of an abstract class need to be implemented in the subclass and an object can be created in the class that extends an abstract class.
  • An abstract class can have constructors and static methods.
  • A class that extends from an abstract class has to implement all the abstract methods of the abstract class.

For example, we have an abstract class Shape and a class named Circle will extend the Shape class:

// abstract class starts with an abstract keyword
abstract class Shape {
    // regular variable 
    String typeOfShape;

    // abstract methods with no body, implementation leaves for the sub class.
    abstract void draw();
    abstract double area();

    // constructor of this abstract class.
    public Shape(String t){
        typeOfShape = t;
    }

    // concrete methods with bodies.

    public String getTypeOfShape() {
        return typeOfShape;
    }
    public String toString() {
        return "Unknown";
    }
}

class Circle extends Shape {
    double radius;
    public Circle (double r, String t){
        super(t);
        this.radius = r;
    }
    
    // overriden methods
    void draw () {
        System.out.println("This is a cirlce");
    }

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

    public String toString() {
        return "The area of this " + this.typeOfShape + " is: " + area(); 
    }

    
}
class Main {
    public static void main(String[] args){
        Circle a = new Circle(1, "Circle");
        System.out.println(a.typeOfShape);
        a.draw();
        System.out.println(a.toString());
    }
}

Output:

Circle
This is a cirlce
The area of this Circle is: 3.141592653589793

What is an interface in Java?

Similar to abstract classes, interfaces in Java help you achieve an abstraction, with abstract classes, the abstraction in range of 0 to 100%, but with interfaces, the abstraction is 100%. Interfaces in Java contain only abstract methods, constant values, static methods, initialized fields, and nested types.

  • Interfaces in Java starts with an interface keyword.
  • Interfaces can not have methods with the body.
  • Interfaces can contain abstract methods, constant values, static methods, initialized fields, and nested types.
  • You cannot create a new object from an interface.
  • Interfaces have no constructor.
  • Everything inside an interface is implicitly public, even when you don’t put the public modifier before your fields.
  • A class implements an interface that needs to override all the abstract methods of the interface.

Example of an interface in Java:

// interface starts with an interface keyword
interface Shape {
    // interface can contain constants, static variables and static methods
    final String shade = "Unknown";
    final int a = 5;
    static float b = 2.3f;
    // static method lies inside this interface and can have the body
    static void info() {
        System.out.println("Interface can have a static method with bodies");
    }

    // abstract methods, implementation is cede for the class implements this interface
    void display();
    double area();
}
class Circle implements Shape {
    // an empty constructor
    Circle() {}

    // overriden methods, have to be public.
    public void display() {
        System.out.println("This is a circle");
    }
    public double area() {
        return Math.PI * Math.pow(a, 2);
    }
}
class Main {
    public static void main(String ...ags){
        // call info() method 
        Shape.info();
        
        Circle x = new Circle();
        x.display();
        System.out.println("This circle has area of " + x.area());

    }
}

Output:

Interface can have a static method with bodies
This is a circle
This circle has area of 78.53981633974483

What is Encapsulation?

Encapsulation is an important OOP concept of data hiding,  this concept is often used to hide the internal representation, or state, of an object from the outside to keep data safe and avoid misuse.

Encapsulation in Java

In Java, encapsulation can be illustrated by making all variables in a class as private and writing public methods to set and get values of variables.

class Person {

    // private variables, cannot be directly accessed by other class.
    private String name;
    private int age;
    private String dateOfBirth;

    // class constructor
    Person (String n, int a, String d){
        this.name = n;
        this.age = a;
        this.dateOfBirth = d;
    }

    // public methods to get the variables information.
    public String getName() {
        return name;
    }
    public int getAge(){
        return age;
    }
    public String getDateOfBirth() {
        return dateOfBirth;
    }

    // public methods to set variables to new values.
    public void setName(String newName){
        this.name = newName;
    }
    public void setAge(int newAge){
        this.age = newAge;
    }
    public void setDateOfBirth(String newD){
        this.dateOfBirth = newD;
    }
}
class Main{
    public static void main(String[] args){

        // First, we create a new object and pass into it 3 arguments
        Person a = new Person("Unknown", 23, "2-20-2020");
        System.out.println(a.getName());
        System.out.println(a.getAge());
        System.out.println(a.getDateOfBirth());
        System.out.println("-------------");
        // indirectly change values of private variables.
        a.setName("No name");
        a.setAge(45);
        a.setDateOfBirth("3-26-1999");
        // variables in Person class are private but their values still can be changed.
        System.out.println(a.getName());
        System.out.println(a.getAge());
        System.out.println(a.getDateOfBirth());
    }
}

Output:

Unknown
23
2-20-2020
-------------
No name
45
3-26-1999
Encapsulation in Java

Advantages of Encapsulation:

  • Data hiding: The inner implementation of the class will be hidden to the user. You only know that we are passing the values to a setter method and variables are getting initialized with that value.
  • Flexibility: With encapsulation, you can either make variables inside a class as read-only or write-only or both depends on our requirements.
  • Reusability: Encapsulation improves the re-usability of our class.

What is Inheritance?

In object-oriented programming, inheritance is the process of using the properties of an existing class and apply to other classes. Also defined as deriving new classes (subclasses) from existing ones (superclass or base class) and forming them into a hierarchy of classes. 

Inheritance in Java

In Java, the ability to create a new class from the existing one is called inheritance. When you inherit from an existing class, you can reuse methods and fields of the parent class and also have their own additional variables, methods, etc…

Essential Terms Used in Inheritance

  • Superclass (parent class): Superclass is a class from where child classes can inherit the features.
  • Child class (derived class): Child class is a class that inherits other classes.
  • Readability: When you create a new class that inherits from an existing one, you can reuse features in the parent class.

Use inheritance in Java

To apply inheritance in Java, we use the extends keyword, as you already saw in some examples above. And the relationship between a parent class and a child class with the extends keyword is considered an IS-A relationship. For example, we have a class named Product and three other classes extend the Product class:

Inheritance in Java

Because three sub-classes extend class Product, then those classes now can reuse what class Product has and with additional features:

  • Product class: productId, name, price
  • ElectricProduct class: productId, name, price, voltage and power
  • CeramicProduct class: productId, name, price, and type.
  • FoodProduct class: productId, name, price, date and expiredDate

Let’s demonstrate inheritance in Java with those classes:

// super class Product 
class Product{
    int productId = 20;
    String name = "Cool Product";
    double price = 39.0d;
}

// subclass ElectricProduct
class ElectricProduct extends Product{
    double voltage = 34;
    double power = 12;
}

// subclass FoodProduct
class FoodProduct extends Product {
    String date = "03-20-2019";
    String expiredDate = "01-19-2020";
}

// subclass CeramicProduct
class CeramicProduct extends Product {
    String type = "A";
}
class Main {
    public static void main(String[] args){
        Product a = new Product();
        ElectricProduct b = new ElectricProduct();
        FoodProduct c = new FoodProduct();
        CeramicProduct d = new CeramicProduct();
        System.out.println("Product: ");
        System.out.println(a.productId + " " + a.name + " " + a.price);

        System.out.println("Electric Product: ");
        System.out.println(b.name + " " + b.name + " " + b.price + " " + b.voltage + " " + b.power);

        System.out.println("Food Product: ");
        System.out.println(c.productId + " " + c.name + " " + c.price + " " + c.date + " " + c.expiredDate);

        System.out.println("Ceramic Product: ");
        System.out.println(d.productId + " " + d.name + " " + d.price + " " + d.type);
    }
}

Output:

Product: 
20 Cool Product 39.0
Electric Product: 
Cool Product Cool Product 39.0 34.0 12.0
Food Product: 
20 Cool Product 39.0 03-20-2019 01-19-2020
Ceramic Product: 
20 Cool Product 39.0 A

The subclasses can reuse what the parent class already has, and adding some additional features if needed.

Types of inheritance in Java:

Java has several types of inheritance, which are:

  • Single inheritance: Subclasses inherit one superclass.
  • Multilevel inheritance: There will be one base class we call it A, and there will be another class B inherits class A, then there will be another class C inherits class B and so on…
  • Hierarchical inheritance: The example above is an example of hierarchical inheritance, one base class serves more than one child class.

What is Polyphomism?

The word Polyphomism means has many forms and can be used in various contexts. In OOP, it describes the concept that objects of different types can be accessed through the same interface. Each type can provide its own, independent implementation of this interface. For example, there is a person and there is another person, both, of course, are human but they have different characteristics, personality, traits, appearance, etc…

Polyphomism in Java

In Java, basically there are two types of Polypomism in Java which are Compiling time Polyphomism and Running time Polyphomism. Polyphomism can be achieved by either overloading or overriding methods.

  • Compiling time polyphomism: also known as static method dispatch, the best example of this is method overloading.
  • Running time polyphomism: also known as dynamic method dispatch, the best example of this is method overriding.
Polyphomism in Java

What is method overloading?

If methods have the same name, but a different number or type of parameters, they are overloaded.  For example:

public void aMethod() {} 
public void aMethod(int a, String b, double c) {}
public void aMethod(String a, int b) { }
public void aMethod(double a) {}

Suppose those methods belong to the same class, we can notice that those methods have identical names and their return type, but the number of argument lists are different. Let’s write some code the demonstrate overloading method:

class Overloadding {
    public void aMethod() {
        System.out.println("A method with no parameter!");
    }
    public void aMethod(int a, String b, double c){
        System.out.println("This method has 3 parameters: " + a + " " + b + " " + c);
    }
    public void aMethod(String a, int b){
        System.out.println("This method has 2 parameter: " + a + " " + b);
    }
    public void aMethod(double a){
        System.out.println("This method has 1 parameter: " + a);
    }
}
class Main{
    public static void main(String[] args){
        Overloadding x = new Overloadding();
        x.aMethod();
        x.aMethod(22.4);
        x.aMethod("A", 3);
        x.aMethod(13, "C", 27.5);
    }
}

Output:

A method with no parameter!
This method has 1 parameter: 22.4
This method has 2 parameter: A 3
This method has 3 parameters: 13 C 27.5

So as the example demonstrates, we can see many forms of methods with identical names with overloading. Now let’s move on overriding methods.

Why is overloading useful?

Imagine methods that calculate the area of a triangle. One such method might take the Cartesian coordinates of the three vertices, and another might take the polar coordinates. This can be done with overloading in Java, but in other languages that don’t support overloading, you have to come up with different names for those methods.

What is method overriding?

If the sub-class has the same method as the method in the parent class, it is considered as a method overriding in Java. And there are a few keynotes about an overriding method:

  • An overriding method replaces the method it overrides.
  • The name, return type, the number of arguments of an overriding method need to be identical as the method it overrides.
  • Each method in the parent class can be overridden at most once in any one subclass.

For example:

// superclass, has one method speak
class Animal {
    void speak() {
        System.out.println("I am saying something! Can you hear?");
    }
}

// class Dog extends Animal and overrides the speak method
class Dog extends Animal {
    void speak() {
        System.out.println("Woof!");
    }
}

// class Cat extends Animal and overrides the speak method
class Cat extends Animal {
    void speak() {
        System.out.println("Meow!");
    }
}
class Main {
    public static void main(String[] args){
        Animal a = new Animal();
        a.speak();
        Animal b = new Dog();
        b.speak();
        Animal c = new Cat();
        c.speak();
    }
}

Output:

I am saying something! Can you hear?
Woof!
Meow!

As shown in the example, we have two classes Dog and Cat extend Animal class and in each subclass we override the speak method, and remember return type, name, and a number of arguments of a method you try to override need to be the same.

What is overriding useful?

The overriding method modifies the implementation of a particular piece of behavior for a subclass. Method overriding is mainly used in a situation when we want to create a more specialized version of a generic method inherited from a superclass, within the subclass.

Wow, it seems a pretty long article, but if you read until the end I really appreciate your effort, from now on I think you have a solid idea about OOP in Java and you can share and explain its concepts to other people. Happy coding and see you in the next article!

Previous Article
Next Article

Sign up for newsletter

* indicates required

Categories

Archives