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
publicgetters 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
abstractthat 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.
- Create an
abstract class Shapewith an abstract methoddouble area()and a regular methodvoid describe()that prints"I am a shape with area: "followed by the result ofarea(). - Create a
Circlesubclass that takes aradiusin its constructor and implementsarea()asMath.PI * radius * radius. - Create a
Rectanglesubclass that takeswidthandheightand implementsarea()aswidth * height. - In
main, create oneCircle(radius 5) and oneRectangle(width 4, height 6), calldescribe()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
privatefields 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
- Oracle Java OOP Concepts — the authoritative Java tutorial on classes, objects, and inheritance
- Effective Java by Joshua Bloch — the definitive guide to writing idiomatic, well-structured Java; OOP principles covered in depth
- Android Developer Guide — Classes and Objects — how OOP maps to Android component design
- ⬅️ Previous: Android Application Components Required to Make an Application
- ➡️ Next: Android Application Structure Folder Structure