Topic 3 of 28 · Android Native Developer

Topic 3: Java Day-I Introduction to OOPS

Lesson TL;DRTopic 3: Java DayI Introduction to OOPS 📖 5 min read · 🎯 beginner · 🧭 Prerequisites: introductiontoandroidosjavaprogramminglanguage, androidapplicationcomponentsrequiredtomakeanapplication Why this...
5 min read·beginner·java · oop · encapsulation · inheritance

Topic 3: Java Day-I Introduction to OOPS

📖 5 min read · 🎯 beginner · 🧭 Prerequisites: introduction-to-android-os-java-programming-language, android-application-components-required-to-make-an-application

Why this matters

Here's the thing — every Android app you've ever used on your phone is made up of objects. A button is an object. A screen is an object. Even the list of messages in WhatsApp is an object. Java, the language we're using to build Android apps, was designed from the ground up around this idea called Object-Oriented Programming, or OOP. Four concepts sit at the heart of it: Encapsulation, Inheritance, Polymorphism, and Abstraction. Once these click for you, writing Java stops feeling like guesswork and starts feeling like building with purpose.

What You'll Learn

  • What the four pillars of OOP are and why they exist
  • How encapsulation protects data using private fields and public getters/setters
  • How inheritance lets subclasses reuse superclass behavior
  • How polymorphism enables one interface to serve many forms via method overriding
  • How abstraction hides complexity behind abstract classes and interfaces

The Analogy

Think of a modern car. The steering wheel, pedals, and dashboard are the public interface — you interact with them without knowing what's happening under the hood (abstraction). The engine internals are locked away inside the chassis so you can't accidentally rewire them (encapsulation). A sports car inherits everything a base car has — engine, wheels, doors — and adds a turbocharger on top (inheritance). And whether you're driving a sedan, a truck, or an SUV, pressing the accelerator always moves the vehicle forward — the same action, different outcomes depending on which vehicle you're in (polymorphism).

Chapter 1: Encapsulation

Encapsulation bundles an object's data (fields) and the methods that operate on that data into a single class, then restricts direct outside access to the fields. This prevents accidental corruption of internal state and forces callers to go through controlled entry points.

The pattern is straightforward:

  • Declare fields private
  • Expose them through public getters and setters
  • Add validation logic inside setters to enforce business rules
public class Person {
    // Private fields
    private String name;
    private int age;

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

    // Public getter for name
    public String getName() {
        return name;
    }

    // Public setter for name
    public void setName(String name) {
        this.name = name;
    }

    // Public getter for age
    public int getAge() {
        return age;
    }

    // Public setter for age — note the validation guard
    public void setAge(int age) {
        if (age > 0) {
            this.age = age;
        } else {
            throw new IllegalArgumentException("Age must be positive");
        }
    }
}

Notice that setAge rejects non-positive values by throwing IllegalArgumentException. Without encapsulation, any caller could write person.age = -5 and your data would silently corrupt.

Chapter 2: Inheritance

Inheritance lets one class (the subclass) acquire the fields and methods of another class (the superclass) using the extends keyword. This avoids duplicating shared behavior across related classes.

Key vocabulary:

  • Superclass (parent) — the class being inherited from
  • Subclass (child) — the class that inherits
  • The subclass can add its own methods on top of what it inherits
// Superclass
public class Animal {
    public void eat() {
        System.out.println("This animal eats food.");
    }
}

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

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();  // Inherited method — outputs: This animal eats food.
        dog.bark(); // Subclass method  — outputs: The dog barks.
    }
}

Dog never defines eat(), yet it can call it because Animal already did the work. Every new animal type you create (Cat, Bird, Fish) gets eat() for free.

Chapter 3: Polymorphism

Polymorphism — Greek for "many forms" — lets one interface represent a general class of actions while the specific behavior is determined at runtime. In Java, polymorphism is primarily achieved through method overriding (runtime polymorphism) and method overloading (compile-time polymorphism).

Method Overriding means a subclass replaces a superclass method with its own version, marked with @Override:

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

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

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Cat(); // superclass reference, subclass object
        myAnimal.makeSound();        // Outputs: The cat meows.
    }
}

The variable myAnimal is declared as Animal, but at runtime Java sees the actual object is a Cat and calls Cat's version of makeSound(). This is the power of polymorphism: you can write code against the Animal type and swap in any subclass without changing the calling code.

Chapter 4: Abstraction

Abstraction hides complex implementation details and exposes only what callers need to know. In Java, abstraction is achieved using:

  • Abstract classes — classes declared with abstract that may contain both abstract methods (no body) and regular methods (with body). Cannot be instantiated directly.
  • Interfaces — fully abstract contracts (covered in depth in later lessons).
// Abstract class
public abstract class Vehicle {
    // Abstract method — no body, subclasses MUST implement this
    public abstract void startEngine();

    // Regular method — subclasses inherit this as-is
    public void stopEngine() {
        System.out.println("Engine stopped.");
    }
}

// Subclass provides the concrete implementation
public class Car extends Vehicle {
    @Override
    public void startEngine() {
        System.out.println("Car engine started.");
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle myCar = new Car();
        myCar.startEngine(); // Outputs: Car engine started.
        myCar.stopEngine();  // Outputs: Engine stopped.
    }
}

Vehicle defines the contract ("every vehicle must be able to start and stop") without dictating how starting works. A Motorcycle, an ElectricCar, or a Truck can each implement startEngine() in their own way while sharing the stopEngine() behavior.

Chapter 5: Putting It Together

Here is how the four pillars relate to each other in practice:

graph TD
    A[OOP in Java] --> B[Encapsulation]
    A --> C[Inheritance]
    A --> D[Polymorphism]
    A --> E[Abstraction]

    B --> B1["private fields + public getters/setters"]
    C --> C1["extends — subclass reuses superclass"]
    D --> D1["@Override — runtime behavior by object type"]
    E --> E1["abstract class / interface — hide complexity"]

    C1 --> D1

Together they produce code that is:

  • Modular — each class has one responsibility (encapsulation)
  • Reusable — common behavior lives in one place (inheritance)
  • Flexible — callers don't need to know which subtype they have (polymorphism)
  • Simple to use — implementation details stay hidden (abstraction)

🧪 Try It Yourself

Task: Build a mini shape hierarchy.

  1. Create an abstract class Shape with an abstract method double area() and a regular method void describe() that prints "I am a shape with area: " followed by the result of area().
  2. Create a Circle subclass that takes a radius in its constructor and implements area() as Math.PI * radius * radius.
  3. Create a Rectangle subclass that takes width and height and implements area() as width * height.
  4. In main, create one Circle (radius 5) and one Rectangle (width 4, height 6), call describe() on each.

Success criterion: You should see output like:

I am a shape with area: 78.53981633974483
I am a shape with area: 24.0

Starter snippet:

public abstract class Shape {
    public abstract double area();

    public void describe() {
        System.out.println("I am a shape with area: " + area());
    }
}

🔍 Checkpoint Quiz

Q1. What is the main purpose of marking a field private and providing a public setter in Java?

A) To make the code compile faster
B) To prevent accidental modification of data by enforcing controlled access
C) To allow the field to be used across multiple packages freely
D) To satisfy the Java compiler's naming conventions

Q2. Given the following code, what does it print?

public class Animal {
    public void makeSound() {
        System.out.println("Generic sound");
    }
}
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        a.makeSound();
    }
}

A) Generic sound
B) Woof
C) Compilation error — cannot assign Dog to Animal
D) Runtime exception

Q3. A class declared abstract in Java:

A) Can be instantiated using new AbstractClassName()
B) Cannot have any regular (non-abstract) methods
C) Cannot be instantiated directly but can be subclassed
D) Is identical to an interface

Q4. You are building an Android app with Button, ImageButton, and RadioButton classes. Each needs a void onClick() method but with different behavior. Which OOP pillar best describes creating a base View class with onClick() that each subclass overrides?

A) Encapsulation
B) Abstraction only
C) Polymorphism via method overriding
D) Neither — this is a design pattern, not an OOP principle

A1. B — Private fields with public setters enforce controlled access. The setter can validate the incoming value (as the setAge example showed, rejecting negative ages) before storing it.

A2. B — Woof. Even though the variable a is declared as Animal, the actual runtime object is a Dog, so Java invokes Dog's overridden makeSound(). This is runtime polymorphism.

A3. C — An abstract class cannot be instantiated with new, but it can be subclassed. Subclasses must implement all abstract methods or also be declared abstract. It can contain both abstract and regular methods, unlike a pure interface.

A4. C — Each subclass providing its own implementation of an inherited method is method overriding, the core mechanism of polymorphism. This lets you write view.onClick() without knowing the exact subtype at compile time.

🪞 Recap

  • The four pillars of OOP are Encapsulation, Inheritance, Polymorphism, and Abstraction — each solving a distinct code-quality problem.
  • Encapsulation uses private fields and public getters/setters to guard data integrity.
  • Inheritance (extends) lets a subclass reuse a superclass's fields and methods without rewriting them.
  • Polymorphism (@Override) allows a superclass reference to behave differently depending on which subclass object it holds at runtime.
  • Abstraction (abstract class) defines a contract of required behavior while hiding implementation details from callers.

📚 Further Reading

Like this topic? It’s one of 28 in Android Native Developer.

Block your seat for ₹2,500 and join the next cohort.