What Is Object-Oriented Programming?
Object-Oriented Programming (OOP) is a way of organizing code around objects — self-contained units that combine data (attributes) and behavior (methods). OOP is the dominant programming paradigm for building large, maintainable applications, and it's central to languages like Java, Kotlin, Python, C++, and JavaScript.
Understanding OOP isn't just about passing interviews — it's about writing code that's easier to maintain, extend, and debug as your projects grow.
The Four Pillars of OOP
1. Encapsulation
Encapsulation means bundling data and the methods that operate on that data together inside a class, and hiding internal details from the outside world. Think of a car: you press the accelerator without needing to understand the engine internals.
In practice, this means marking class fields as private and providing public getter/setter methods to control access. This protects your data from being accidentally corrupted by outside code.
class BankAccount(private var balance: Double) {
fun deposit(amount: Double) {
if (amount > 0) balance += amount
}
fun getBalance(): Double = balance
}
The balance can't be modified directly from outside the class — only through the controlled deposit method.
2. Inheritance
Inheritance allows one class (the child/subclass) to take on the properties and methods of another class (the parent/superclass). This promotes code reuse and creates logical hierarchies.
open class Animal(val name: String) {
fun eat() = println("$name is eating")
}
class Dog(name: String) : Animal(name) {
fun bark() = println("$name says woof!")
}
Dog inherits the eat() method from Animal and adds its own bark() method. The key principle: use inheritance to model is-a relationships (a Dog is an Animal).
3. Abstraction
Abstraction means exposing only the essential features of an object, hiding the complex implementation details. Abstract classes and interfaces define a contract — what an object can do — without specifying exactly how.
abstract class Shape {
abstract fun area(): Double
fun describe() = println("This shape has area: ${area()}")
}
class Circle(private val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
}
Any Shape subclass must implement area(), but describe() works without knowing anything about the specific shape.
4. Polymorphism
Polymorphism means "many forms." It allows objects of different types to be treated as objects of a common type, with each responding to the same method call in its own way.
val shapes: List<Shape> = listOf(Circle(5.0), Rectangle(4.0, 6.0))
shapes.forEach { it.describe() } // Each shape calculates its own area
You can loop through a list of different shapes and call describe() on all of them — each one handles it differently behind the scenes.
OOP vs. Procedural Programming
| Aspect | Procedural | OOP |
|---|---|---|
| Code organization | Functions and procedures | Classes and objects |
| Data handling | Separate from functions | Bundled with methods |
| Code reuse | Function calls | Inheritance and composition |
| Best for | Scripts, small tools | Large, complex applications |
When to Use OOP
OOP shines when you're building applications with multiple entities that have both state and behavior — like user accounts, products, or UI components. It's not always the right tool: small scripts and data-processing tasks are often simpler with functional or procedural approaches.
Key Takeaway
OOP is a mental model for organizing complexity. Master the four pillars, and you'll write code that's easier to read, test, and scale. The best way to internalize these concepts is to build a project using them — create a simple class hierarchy for something you find interesting and watch the ideas click into place.