Object Oriented Programming in Java

Object Oriented Programming in Java

The Concepts of Object Oriented Programming, summarized in Java programming language.

Part 2: OOPs.

Find part 1 here.


The concept of OOPs (Object Oriented Programming) involves a style of coding that binds data and functions into classes and objects. This improves the readability, reusability and overall efficiency of a program. Java revolves around this concept.

The main principles of object-oriented programming are abstraction, encapsulation, inheritance, and polymorphism. These concepts aim to implement real-world entities in programs.

What is an Object?

An Object is an instance of a class. They are like an implementation of real-life entities. For example, if the class is "Operating system", possible objects can be "Windows", "iOS", "Linux" etc. As understood from the example, every object is unique in itself and also has some common features that it shared with other objects thus making them all a part of the class named operating system.

Every object has a state and behaviour. State of an object tells about the attributes or qualities of the object. Behaviour of an object tells about the tasks or functions the object can perform. Various objects of the same class share the same behaviour but have unique states.

What is a Class?

A class is a template for creating objects. It is not a real-world entity, just a blueprint from which objects are created. Classes don’t consume any space in the memory. They have members which can be data types, methods and constructors.

A class declaration consists of:

  1. Modifiers: These can be public or default access.

  2. Class name: Name of class.

  3. Superclass: A class may inherit the properties of another class.

  4. Interfaces: A class can implement more than one interface.

  5. Body: Body surrounded by braces, { }.

public class OperatingSystem {
    private String name;
    private int version;
    // Constructor
    public OperatingSystem(String name, int version) {
        this.name = name;
        this.version = version;
    }
    // Input methods
    public String getName() {
        return name;
    }
    public int getVersion() {
        return version;
    }

    public static void main(String[] args) {
        // Creating objects of the OperatingSystem class
        OperatingSystem windows = new OperatingSystem("Windows", 10);
        OperatingSystem mac = new OperatingSystem("MacOS", 11);

        // Displaying states of both objects
        System.out.println("Operating System 1: " + windows.getName() + " (Version " + windows.getVersion() + ")");
        System.out.println("Operating System 2: " + mac.getName() + " (Version " + mac.getVersion() + ")");
    }
}

Access Modifiers in Java

There are four types of access modifiers available in Java:

  1. Default: When no access modifier is specified for a class, method, or data member, it is said to be having the default access modifier by default. The data members, classes, or methods that are not declared using any access modifiers i.e. having default access modifiers are accessible only within the same package.

  2. Public: The public access modifier is specified using the keyword public. The public access modifier has the widest scope among all other access modifiers. Classes, methods, or data members that are declared as public are accessible from everywhere in the program. There is no restriction on the scope of public data members.

  3. Private: The private access modifier is specified using the keyword private. The methods or data members declared as private are accessible only within the class in which they are declared.

Protected: The protected access modifier is specified using the keyword protected. The methods or data members declared as protected are accessible within the same package or subclasses in different packages.

The 4 main concepts of OOPs

The 4 main core concepts of OOPs that are also referred to as the four pillars of OOPs are as follows:

  • Abstraction

  • Encapsulation

  • Inheritance

  • Polymorphism

Let's discuss them in brief.

What is Abstraction?

Abstraction is a process that displays only the information needed and hides unnecessary information. We can say that the main purpose of abstraction is data hiding. Abstraction means selecting data from a large number of data to show the information needed, which helps reduce programming complexity and writing. For example, while driving a car, the driver only needs to know how or when to turn the steering, not how the steering can turn the wheels. In Java, abstraction is achieved by interfaces and abstract classes.

There are instances where it is necessary to establish a superclass that outlines the framework of a particular concept without fully implementing every method. Occasionally, we may require a superclass that merely establishes a generalized form, which will be inherited by all its subclasses, allowing each subclass to individually incorporate specific details.

What is Encapsulation?

Encapsulation is an important concept in object-oriented programming (OOP). It involves putting data and code together in a single package and protecting them from outside interference. It's like wrapping them up in a safe wrapper. With encapsulation, the data is hidden from other parts of the program and can only be accessed through specific methods. This is called "data hiding." Encapsulation ensures that only authorized code can work with the data.

To achieve encapsulation, we make the variables private and provide public methods to change or view the variable values. This way, we control how the data is accessed and modified. Encapsulation also makes the code more reusable and easier to test. It provides a clear interface for interacting with the data, making it easier to verify its behavior in isolation.

What is Inheritance?

Inheritance is a way for one object to inherit or acquire the characteristics of another object. It's like passing down traits from one generation to another. With inheritance, we can create new classes based on existing classes. When we inherit from a class, we can reuse the methods and attributes of the original class. Inheritance helps organize objects into a hierarchical structure, where there are parent and child relationships between classes.

The subclass is a class which inherits properties of the superclass. This is also called a derived class. A superclass is a base class or parental class from which a subclass inherits properties.

There are five types of inheritance single, multilevel, multiple, hybrid and hierarchical.

  1. Simgle Inheritance: One derived class inherits properties from its parental class.

     Class a {
     …
     }
     Class b extends class a {
     …
     }
    
  2. Multilevel Inheritance: a derived class inherits from a base class, which itself inherits from another base class, creating a chain of inheritance relationships.

     Class a {
     ….
     }
     Class b extends class a {
     ….
     }
     Class c extends class b {
     … 
     }
    
  3. Multiple Inheritance: a derived class can inherit from more than one base class, allowing it to acquire attributes and behavior from multiple parent classes. It is not directly supported in Java and can be implemented using interfaces.

     interface a {
     ….
     }
     interface b  {
     ….
     }
     Class c implements a, b {
     … 
     }
    
  4. Hierarchal Inheritance: one parental class has two or more derived classes

     Class a {
     …
     }   
     Class b extends class a {
     ..
     }
     Class c extends class a {
     ..
     }
    
  5. Hybrid Inheritance: This is the combination of multiple and multilevel inheritances and in java, multiple inheritances are not supported as it leads to ambiguity and this type of inheritance can only be achieved through interfaces.

     interface A {
         void method1();
     }
    
     interface B1 extends A {
         void method2();
     }
    
     interface B2 {
         void method3();
     }
    
     class C implements B1 {
         public void method1() {
             System.out.println("C - Method 1");
         }
    
         public void method2() {
             System.out.println("C - Method 2");
         }
    
         public void method4() {
             System.out.println("C - Method 4");
         }
     }
    
     class D implements B1, B2 {
         public void method1() {
             System.out.println("D - Method 1");
         }
    
         public void method2() {
             System.out.println("D - Method 2");
         }
    
         public void method3() {
             System.out.println("D - Method 3");
         }
    
         public void method5() {
             System.out.println("D - Method 5");
         }
     }
    
     public class Main {
         public static void main(String[] args) {
             D d = new D();
    
             d.method1();
             d.method2();
             d.method3();
             d.method5();
         }
     }
    

What is Polymorphism?

Polymorphism means having many forms or ways of doing something. It occurs when we have different classes that are related through inheritance. There are two types of polymorphism: compile-time polymorphism and runtime polymorphism. An example of compile-time polymorphism is when we have multiple methods with the same name but different parameters. Runtime polymorphism, also known as dynamic method dispatch, is when the specific method to be called is determined during runtime based on the actual object. Polymorphism is achieved through method overloading and method overriding. It simplifies complexity by using a common interface with multiple methods, allowing different actions to be performed using the same interface.

Constructors on Java

In Java, constructors are special methods used to set up objects when they are created. They are called automatically when an object is created using the new keyword. There are different types of constructors:

  1. Default Constructor: It is automatically created by Java if no other constructor is defined. It has no parameters and sets up the object with default values.

  2. Parameterized Constructor: It allows you to pass values when creating an object. It initializes the object with the provided values.

  3. Copy Constructor: It makes a new object by copying the values of another object. It helps create a separate copy of an existing object.

  4. Private Constructor: It is a constructor that can only be used within the class itself. It is used for specific purposes like singleton patterns or utility classes.

Constructor Overloading: Constructor overloading is a feature in Java that allows a class to have multiple constructors with different parameter lists. By providing multiple constructors, you can create objects with different sets of initial values or initialization options. Each constructor can take a different number or types of parameters, allowing for flexibility in object creation.

When an object is created using the new keyword, the appropriate constructor is selected based on the arguments provided. Java matches the arguments to the constructor parameter list, and if a matching constructor is found, it is called to initialize the object.

Constructor overloading enables you to create objects with varying initialization requirements without needing to create separate methods for each case. It simplifies object creation by providing different ways to construct objects based on specific needs or input data.

For example, a person class might have a default constructor with no arguments and another constructor that takes parameters such as name, age, and address. With constructor overloading, you can create a person object using either the default constructor or provide specific values for the parameters, depending on the desired initialization.

class Person {
    String name;
    int age;

    // Default constructor
    Person() {
    }

    // Constructor with parameters
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Method to display person details
    void displayDetails() {
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
    }
}

public class Main {
    public static void main(String[] args) {
        Person person1 = new Person();
        person1.displayDetails();

        Person person2 = new Person("John Doe", 25);
        person2.displayDetails();
    }
}

Coupling in Java

Coupling refers to the relationship between two classes. It shows how much one class knows about the other. If one class changes something, it can impact the other class that depends on it. This means that changes in one class can affect the other class because they are closely connected. The extent of this interdependence determines the level of coupling between the two classes. There are two types of coupling: tight coupling and loose coupling. Tight coupling means the classes are highly dependent on each other, while loose coupling means they are less dependent and can be easily modified or replaced without affecting other classes as much.

Cohesion in Java

In Java, cohesion refers to how well the methods and attributes of a class are connected and focused on a specific task for the system. It measures the degree to which a class has a clear and focused responsibility. Classes with high cohesion are better because they are more reusable and easier to maintain. They have a strong logical relationship between their methods and properties. On the other hand, classes with low cohesion are harder to maintain as they lack a clear and meaningful connection between their methods and properties. It is always recommended to have highly cohesive classes that are focused on a single task, as it leads to better code organization and maintainability.

Association in Java

Association is a connection between two classes that is established through their objects. It describes the relationship between multiple objects. Associations can take different forms, such as one-to-one, one-to-many, many-to-one, and many-to-many. To understand this, let's consider a different example: the relationship between a school and its students. A school can have many students (one-to-many), and each student is associated with only one school (many-to-one). Additionally, a student can be associated with multiple schools if they attend different institutions (many-to-many). Through association, objects can utilize the functionality and services provided by other objects, creating a connection between them based on their specific relationship.

Aggregation: In Java, aggregation refers to a weaker form of association that represents a relationship between an object and other objects it contains. It represents a "part-of" relationship, where the individual parts can exist independently of the whole. Let's use an example of the relationship between a Library and Books. A Library can have many Books, and each Book can be part of multiple Libraries. However, if we delete a Library, the Book objects will still exist. Aggregation signifies a "Has-A" relationship, which is a one-way relationship. For example, a Library can have Books, but the reverse is not true, making it unidirectional. In this type of association, both entities can exist independently, meaning that changing or removing one entity does not affect the other entity. Therefore, both objects remain independent in an aggregation relationship.

Composition: In Java, composition is an association that represents a relationship between a whole and its parts. It signifies a "part-of" relationship where a part cannot exist without the whole. Let's consider an example of the relationship between a House and its Rooms. The House object consists of several Rooms. If the House object is destroyed, all the Room objects associated with it will also be destroyed. This means that without the House object, the dependent Room objects cannot exist. Composition represents a strong association, and it represents the part-of relationship. When the whole object is deleted, all the parts associated with it are also deleted. Therefore, composition ensures that the parts are tightly connected to the whole and cannot exist independently.


Thank you. :)