Mastering Android Kotlin OOP: Classes, Constructors, Inheritance, and Beyond

 

Unit 3 · Android Development

Object-Oriented
Programming in Kotlin

The backbone of modern Android development — classes, objects, inheritance, polymorphism, and everything in between.

🔒
Encapsulation
Keeps data safe
🧬
Inheritance
Code reuse
🔀
Polymorphism
Flexible code
🎭
Abstraction
Hides complexity
01

Introduction to OOP in Kotlin

Object-Oriented Programming is the backbone of modern Android development. If you've ever built an Android app — even a simple one — you've already used classes, objects, and probably inheritance without fully realizing the depth behind them.

Think of OOP in Kotlin like building with LEGO blocks. Each block is a class. You create copies of those blocks — those are your objects. You can extend them, modify them, and combine them to create complex systems. That's exactly how Android apps are structured under the hood.

// OOP Mental Model

Understanding these core building blocks gives you total control over how your application behaves and scales. Kotlin makes OOP not just powerful but surprisingly elegant — removing boilerplate, simplifying syntax, and allowing you to focus on logic rather than structure.

02

Why Kotlin is Perfect for Android

Kotlin became Google's preferred Android language because it blends simplicity with power. It reduces common errors like null pointer exceptions and eliminates unnecessary verbosity found in Java.

95% of the top 1,000 Android apps now use Kotlin,
either fully or partially — it's an industry shift.

Kotlin's support for OOP is clean and intuitive. It allows you to declare properties directly in constructors, supports extension functions, and simplifies inheritance. The result? Faster development, fewer bugs, and more maintainable code.

03

Classes & Objects

Classes are blueprints. Objects are real-world instances of those blueprints. In Android development, almost everything revolves around classes — Activities, Fragments, ViewModels, and even layouts indirectly.

Blueprint
Class
Defines properties, methods, and behavior — the architectural design of a building.
Instance
Object
A real, usable copy of the class — the actual building constructed from the design.

Defining a Class in Kotlin

Defining a class is refreshingly simple. You use the class keyword followed by the class name. Unlike Java, Kotlin allows you to define properties directly in the constructor, reducing redundancy significantly:

class User(val name: String, var age: Int) {
    fun greet() {
        println("Hello, I'm $name and I'm $age years old.")
    }
}

// Creating an object (instance)
val user = User("Alex", 28)
user.greet()  // Hello, I'm Alex and I'm 28 years old.
04

Constructors in Kotlin

Constructors are special functions used to initialize objects. Kotlin supports both Primary and Secondary constructors, giving you full flexibility in object creation.

Primary Constructor

Defined directly in the class header — concise and centralized. When you declare variables with val or var in the constructor, Kotlin automatically generates getters and setters where needed:

class Product(val id: Int, val name: String, var price: Double)

Secondary Constructor

Defined inside the class body for alternative initialization scenarios — useful when data comes from different sources like a network response vs a local database:

class Product(val name: String) {
    var price: Double = 0.0

    constructor(name: String, price: Double): this(name) {
        this.price = price
    }
}
05

Properties & Methods

Properties represent data, while methods define behavior. Together, they form the core functionality of any Kotlin class.

val
Immutable Property
Preferred when possible. Prevents unintended modifications and improves predictability.
var
Mutable Property
Use when the value needs to change. Supports custom getters and setters.
fun
Methods
Define actions: handle clicks, call APIs, process data. Each method should do one clear task.
class Circle(val radius: Double) {
    val area: Double
        get() = Math.PI * radius * radius  // Custom getter

    fun describe() = "Circle with radius $radius"
}
06

Access Modifiers

Access modifiers control visibility and enforce encapsulation. Think of them as security clearance levels in a building — not everyone gets access to every floor.

Modifier Scope Best Used For
public Accessible everywhere (default) Public APIs and shared interfaces
private Within the same class only Internal implementation details
protected Class and its subclasses Shared logic in inheritance hierarchies
internal Within the same module Module-level utilities and helpers
🏗️
Why restrict access? It enforces encapsulation, prevents external classes from tampering with sensitive logic, reduces bugs, and keeps your Android architecture clean and predictable.
07

Inheritance in Kotlin

Inheritance allows one class to inherit properties and methods from another, enabling code reuse and logical hierarchy.

🔑
Key rule: By default, Kotlin classes are final and cannot be subclassed. You must explicitly use the open keyword to allow inheritance — this prevents accidental subclassing and enforces intentional design.
open class Animal(val name: String) {
    open fun sound() = "..."
}

class Dog(name: String) : Animal(name) {
    override fun sound() = "Woof!"  // Overriding parent method
}

val dog = Dog("Rex")
println(dog.sound())  // Woof!
08

Polymorphism in Kotlin

Polymorphism allows objects to behave differently based on context. In Android, this powers dynamic UI updates, RecyclerView adapters, ViewModels, and sealed classes.

Compile-Time
Function Overloading
Same function name, different parameters. Resolved at compile time.
Runtime
Method Overriding
Subclass replaces parent behavior. Resolved dynamically at runtime.
09

Abstract Classes & Interfaces

Abstract Classes

Abstract classes cannot be instantiated directly. Use them when multiple subclasses share common structure but require different implementations — they define what must be implemented, while concrete classes define how.

abstract class Shape {
    abstract fun area(): Double
    fun describe() = "I am a shape with area ${area()}"
}

class Rectangle(val w: Double, val h: Double) : Shape() {
    override fun area() = w * h
}

Interfaces

Interfaces define contracts — abstract methods that implementing classes must define. Unlike abstract classes, Kotlin supports multiple interface implementation, enabling flexible design patterns:

interface Clickable {
    fun onClick()
}

interface Swipeable {
    fun onSwipe()
}

class CardView : Clickable, Swipeable {  // Multiple interfaces
    override fun onClick() { println("Tapped!") }
    override fun onSwipe() { println("Swiped!") }
}
10

Data Classes & Companion Objects

Data Classes

Data classes automatically generate toString(), equals(), hashCode(), and copy(). They are perfect for API models and database entities:

data class User(val id: Int, val name: String, val email: String)

val user1 = User(1, "Alex", "alex@mail.com")
val user2 = user1.copy(name = "Sam")  // New object with updated name

Companion Objects

Companion objects allow you to define static-like members inside classes — useful for constants, factory methods, and singleton patterns:

class ApiClient {
    companion object {
        const val BASE_URL = "https://api.example.com"
        fun create(): ApiClient = ApiClient()  // Factory method
    }
}

println(ApiClient.BASE_URL)  // Accessed without creating an instance

Topics covered in this unit:

Classes & Objects Constructors Properties Access Modifiers Inheritance Polymorphism Abstract Classes Interfaces Data Classes Companion Objects

Conclusion

Mastering OOP in Kotlin gives you a powerful toolkit for Android development. These concepts are not isolated theories — they form the structure of every scalable Android application.

Once you understand how they connect, your code becomes cleaner, more maintainable, and easier to extend.

"Android development stops feeling chaotic
and starts feeling intentional."

FAQ

Frequently Asked Questions

Why are Kotlin classes final by default?
To prevent unintended inheritance and encourage safer, more intentional design. You must use the open keyword explicitly to allow subclassing.
When should I use a data class?
When representing pure data models like API responses or database entities — they automatically generate equals(), hashCode(), toString(), and copy().
What is the difference between abstract classes and interfaces?
Abstract classes can hold state (properties with values), while interfaces define behavior contracts. A class can implement multiple interfaces but can only extend one abstract class.
Why use companion objects?
To simulate static behavior, create factory methods, and hold module-level constants — all without needing to instantiate the class first.
Is polymorphism important in Android development?
Yes — it powers flexible UI components, RecyclerView adapters, sealed classes, and scalable architecture patterns like MVVM and Clean Architecture.


Post a Comment

0 Comments