What is Object-Oriented Programming?
Object-Oriented Programming (OOP) is a programming paradigm that organises code around objects — self-contained units that bundle data (properties/fields) with the functions that operate on that data (methods). OOP contrasts with procedural programming, where code is organised as a sequence of functions that operate on separate data structures.
The key insight of OOP is modelling software around real-world entities. A BankAccount object knows its own balance and can deposit, withdraw, and check its balance. It protects its internal state from direct manipulation — you use its public methods, not poke at its internal fields.
| Aspect | Procedural | Object-Oriented |
|---|---|---|
| Code organisation | Functions + data structures | Objects (data + behaviour together) |
| Data access | Global or passed as parameters | Encapsulated inside objects |
| Reuse mechanism | Function calls, includes | Inheritance, composition |
| Typical languages | C, Pascal, early PHP/Python | Java, C#, Python, PHP, JavaScript |
| Best for | Scripts, utilities, systems code | Large, complex, long-lived applications |
Classes and Objects
A class is a blueprint that defines what properties and methods an object will have. An object is a specific instance of that class — created with the new keyword in most languages.
Pillar 1: Encapsulation
Encapsulation bundles data and methods into a single unit (the class) and restricts direct access to internal state. The object exposes a controlled public interface — while hiding implementation details.
Why it matters: Without encapsulation, any code can reach in and change account.balance = -99999 directly. With encapsulation, you call account.withdraw(amount) which validates the amount first.
Access Modifiers
Most OOP languages provide: private (accessible only within the class), protected (accessible within the class and subclasses), public (accessible from anywhere). Use the most restrictive access level that works — default to private for fields.
Pillar 2: Inheritance
Inheritance allows a child class to reuse and extend the behaviour of a parent class. The child class inherits all non-private fields and methods, and can add new ones or override existing ones.
Pillar 3: Polymorphism
Polymorphism means "many forms" — the same method name behaves differently depending on the object's actual type. This allows you to write code that works with a general type (Animal) and have the correct specific behaviour invoked at runtime.
Polymorphism eliminates if/else chains like if (animal instanceof Dog) { dog.eatDogFood(); } else if (animal instanceof Cat) {...}. The correct method is dispatched automatically.
Pillar 4: Abstraction
Abstraction means exposing only the essential features of an object while hiding the complex implementation details. This is achieved through abstract classes and interfaces.
Inheritance vs Composition
One of the most debated OOP design decisions is inheritance versus composition. Both are valid but serve different purposes:
| Property | Inheritance (is-a) | Composition (has-a) |
|---|---|---|
| Relationship | Dog IS-A Animal | Car HAS-A Engine |
| Coupling | Tight — child depends on parent | Loose — components are independent |
| Flexibility | Less flexible — hierarchy is fixed | Highly flexible — swap components |
| Code reuse | Automatic through inheritance chain | Explicit — delegate to composed objects |
| Testing | Harder — must test full hierarchy | Easier — test each component in isolation |
| When to use | Genuine is-a, stable hierarchy | Prefer this in most cases |
Avoid Deep Inheritance Hierarchies
Hierarchies deeper than 2-3 levels become difficult to reason about and maintain. When you find yourself writing Animal → Mammal → Pet → DomesticAnimal → Dog → PoliceDog chains, reconsider using composition instead. Changes to the top of the hierarchy ripple unpredictably down.
Abstract Classes vs Interfaces
| Property | Abstract Class | Interface |
|---|---|---|
| Can have concrete methods | Yes | Java 8+: default methods; traditionally no |
| Can have fields | Yes | Only constants (static final) |
| Constructor | Yes | No |
| Multiple inheritance | One only (extends) | Multiple (implements many interfaces) |
| Use when | Shared code among related classes | Define a contract for unrelated classes |
| Example | AbstractBaseView with render logic | Serializable, Comparable, Printable |
How We Research and Update This Guide
We test the underlying formula or workflow, compare outputs with reliable references, and revise examples whenever the page content changes.
- The workflow or formula is tested directly in the tool and compared against independent reference examples.
- Examples are kept practical so readers can verify the result without hidden assumptions.
- Pages are revised whenever the interface, calculation flow, or surrounding guidance materially changes.
Frequently Asked Questions — OOP Concepts
Encapsulation — bundling data (fields) and methods that operate on it into one class, hiding internal details. Inheritance — a child class reuses and extends a parent class's behaviour. Polymorphism — the same interface can work with different types; a method behaves differently based on the object's actual type. Abstraction — expose only what is necessary; hide implementation details behind interfaces or abstract classes.
A class is a blueprint or template — it defines properties and methods but does not occupy memory by itself. An object is an instance of a class — a concrete entity in memory created from the blueprint. Example: Car is a class defining colour, speed, start(), stop(). My red Toyota Corolla is an object — a specific instance of Car with actual values.
Inheritance models "is-a" relationships (Dog is-a Animal). Composition models "has-a" relationships (Car has-a Engine). Inheritance is tighter coupling — child classes depend on parent implementation. Composition is more flexible — you can swap components. The "Composition over Inheritance" principle says prefer composition because it avoids deep inheritance hierarchies and tight coupling. Inheritance is appropriate when the is-a relationship is genuine and stable.
Overriding happens in inheritance — a child class provides its own implementation of a method defined in the parent class. Same name, same signature, different behaviour. Overloading is defining multiple methods with the same name but different parameters in the same class. Java supports both; Python supports overriding but not true overloading (uses default arguments instead).
An abstract class can have both abstract methods (no body) and concrete methods (with body). It can have fields and constructors. A class can extend only one abstract class. An interface defines only method signatures (in traditional OOP) — no implementation. A class can implement multiple interfaces. Use abstract class when subclasses share significant common code. Use interface when you want to define a contract that unrelated classes can implement.
SOLID is five design principles for OOP: S — Single Responsibility (one class, one reason to change), O — Open/Closed (open for extension, closed for modification), L — Liskov Substitution (subtypes must be substitutable for their base types), I — Interface Segregation (many specific interfaces over one general), D — Dependency Inversion (depend on abstractions, not concretions). SOLID makes OOP code maintainable, testable, and extensible.