chaidocs
Java Oops

Modern and Practical Oops

Suraj Kumar Jha 31 pages 4 min read Updated Sep 29, 2026
On this page
  1. Phase 4: Modern Practical OOP
  2. Interface = A Contract
  3. Abstract Methods
  4. Default Methods (Java 8)
  5. Why Default Methods Exist
  6. Static Methods in Interfaces
  7. Private Methods (Java 9)
  8. Interface Constants
  9. Multiple Interfaces
  10. Default Method Conflict
  11. Functional Interfaces
  12. Built-in Functional Interfaces
  13. Enum = Fixed Set of Options
  14. Why Enums Beat Strings
  15. Enums with Fields & Methods
  16. Handy Enum Methods
  17. Enums Under the Hood
  18. Records: Data With Less Code
  19. Using a Record
  20. Records Are Immutable (Shallowly)
  21. Compact Constructor
  22. Record Rules
  23. Sealed Classes: Controlled Inheritance
  24. Permitted Subclass Choices
  25. Why Sealed + Pattern Matching
  26. Immutable Objects
  27. Making a Class Immutable
  28. Defensive Copies
  29. Good OOP Habits (1)
  30. Good OOP Habits (2)
  31. The Big Picture

Phase 4: Modern Practical OOP

01 A roadmap with five milestones labelled Interfaces, Enums, Records, Sealed, Immutability
Notes
Five topics in this phase: • Interfaces (deep dive) • Enums, Records, Sealed Classes • Immutable objects & good design habits

Interface = A Contract

02 A contract document labelled 'Payment' with arrows to UPI, Card, Cash signing it
Notes
An interface lists behaviours a class MUST provide. Interface says WHAT should happen; the class decides HOW. Example: interface Payment { void pay(double amount); } class UPI implements Payment must write its own pay().

Abstract Methods

03 Empty method box in interface, filled-in box in UPI class below it
Notes
Declared in an interface with no body: void pay(double amount); Java silently treats it as public abstract. Every implementing class must fill in the body. Interface = what; Class = how.

Default Methods (Java 8)

04 Interface handing a ready-made 'receipt' tool to UPI, while Card holds its own custom version
Notes
A method inside an interface that already has a body. Implementing classes get it for free, e.g. UPI can call generateReceipt(). A class can still override it, like Card does with its own receipt.

Why Default Methods Exist

05 Many class boxes; red cracks for 'new abstract method' vs green checks for 'default method'
Notes
Imagine thousands of classes implement Payment. Adding a new abstract method would break all of them. A default method adds new behaviour without breaking old code.

Static Methods in Interfaces

06 Payment interface with a toolbox attached; UPI class reaching for it and blocked by a cross
Notes
Belong to the interface itself, not objects. Call as Payment.paymentInfo() ✓ UPI.paymentInfo() ✗ — not inherited by classes. Use them for interface-level utilities.

Private Methods (Java 9)

07 Interface box with a locked inner room 'logTransaction' used only by generateReceipt
Notes
Internal helpers shared by methods inside the interface. Example: generateReceipt() calls private logTransaction(). Outside code cannot call it: upi.logTransaction() ✗

Interface Constants

08 A stone tablet engraved 'PLATFORM_FEE = 2.0' with a padlock
Notes
Variables in an interface are automatically public static final. double PLATFORM_FEE = 2.0; Access via Payment.PLATFORM_FEE. Cannot change it: Payment.PLATFORM_FEE = 10 ✗

Multiple Interfaces

09 UPI class with two plugs connecting into Payment and Refundable sockets
Notes
A class cannot extend two classes: class C extends A, B ✗ But it can implement many interfaces. Example: class UPI implements Payment, Refundable — so it can pay() and refund().

Default Method Conflict

10 Two arrows labelled A.show() and B.show() colliding at Demo, with a referee resolving them
Notes
Interfaces A and B both have default show(). Class Demo implements A, B must override show(). Inside, pick versions using A.super.show() and B.super.show().

Functional Interfaces

11 Calculator interface with one slot, a lambda '(a,b) -> a+b' plugging into it
Notes
An interface with exactly one abstract method, marked @FunctionalInterface. Default methods are still allowed. Can be written as a lambda: Calculator add = (a, b) -> a + b;

Built-in Functional Interfaces

12 Four small machines: a yes/no gate, a converter, a sink, and a dispenser
Notes
Predicate: tests a condition → isEven.test(10) Function: converts input to output → getLength.apply("Java") Consumer: takes input, returns nothing → prints a message Supplier: takes nothing, gives a value → getGreeting.get()

Enum = Fixed Set of Options

13 A weekday dial that can only point to the seven listed days
Notes
A special type for a fixed list of constants. enum Day { MONDAY, TUESDAY, ... SUNDAY } Day today = Day.MONDAY; today can only hold one of those values.

Why Enums Beat Strings

14 A free-text box full of typos vs a clean dropdown with three options
Notes
String status = "SUCCESS" allows typos and junk values. enum Status { PENDING, SUCCESS, FAILED } gives type safety. Status.INVALID ✗ — the compiler rejects it.

Enums with Fields & Methods

15 Three badges LOW=1, MEDIUM=2, HIGH=3 each carrying a small data tag
Notes
Enums can have fields, constructors and methods like classes. LOW(1), MEDIUM(2), HIGH(3) each store a value. Level.HIGH.getValue() prints 3. Enum constructors are implicitly private.

Handy Enum Methods

16 Three labelled buttons: values(), valueOf(), name() with sample outputs
Notes
values() → all constants, useful in loops. valueOf("MONDAY") → string to enum constant. name() → the constant's name, e.g. MONDAY.

Enums Under the Hood

17 Tree: Status at top with three object nodes PENDING, SUCCESS, FAILED
Notes
Not just strings — each constant is a real object. PENDING, SUCCESS, FAILED are predefined Status instances. You can't do new Status() ✗ — Java creates and manages them. Uses: Role, Day, OrderState (CREATED, SHIPPED, DELIVERED).

Records: Data With Less Code

18 A long traditional class shrinking into a one-line record
Notes
A special class for storing immutable data. record User(String name, int age) { } Java auto-generates constructor, accessors, equals(), hashCode(), toString(). Great for DTOs, API responses, config data.

Using a Record

19 A User card showing name: Rahul, age: 20 with accessor arrows
Notes
User user = new User("Rahul", 20); Read values with user.name() and user.age(). Note: name(), not getName(). Can add custom methods, e.g. isAdult() returns age >= 18.

Records Are Immutable (Shallowly)

20 Sealed box labelled Rahul, a new box labelled Aman beside it, and a list peeking out of a crack
Notes
No setters; user.name = "Aman" ✗ Need a change? Create a new record: new User("Aman", 20). Caution: a mutable field like List<String> roles can still be modified inside.

Compact Constructor

21 A security gate checking 'age < 0?' before letting data into the record
Notes
Used mainly for validation. User { if (age < 0) throw new IllegalArgumentException(...); } No need to write this.name = name — the record assigns fields itself.

Record Rules

22 Checklist with ✓ for interfaces/static and ✗ for extends/extra fields
Notes
Implicitly final; cannot extend another class. No extra instance fields beyond its components. Can have static fields/methods and implement interfaces. Record = concise, data-focused class with built-in value behaviour.

Sealed Classes: Controlled Inheritance

23 Animal with a guest list letting in Dog and Cat, Horse stopped at the door
Notes
Normally any accessible class can extend Animal. sealed class Animal permits Dog, Cat { } Now only Dog and Cat may extend it. class Horse extends Animal → compile error.

Permitted Subclass Choices

24 Hierarchy: Animal → Dog (final) and Cat (non-sealed) → PersianCat
Notes
Each permitted subclass must declare one: • final — nobody can extend it further • sealed — keep restricting (Cat permits PersianCat) • non-sealed — opens the branch to anyone

Why Sealed + Pattern Matching

25 Payment splitting into exactly two labelled paths: Card and UPI
Notes
You know exactly which types exist, e.g. sealed interface Payment permits Card, UPI. Compiler knows all options when you check instanceof Card / UPI. Useful for domain models, state machines, API responses, ASTs.

Immutable Objects

26 A frozen ice-block object labelled Rahul, 20 beside a fresh one labelled Rahul, 25
Notes
State cannot change after creation. User user = new User("Rahul", 20); — no setAge() ✗ Need a new state? Create a new object: new User("Rahul", 25). Known examples: String, Integer, Long, Double, LocalDate.

Making a Class Immutable

27 A seven-step checklist next to a locked safe
Notes
Class final; fields private and final. Set all fields in the constructor; no setters. Don't expose mutable internals; use defensive copies. Benefits: safer sharing, fewer accidental changes, good for concurrency and hash keys.

Defensive Copies

28 Original list being photocopied; the object keeps the copy in a locked drawer
Notes
Storing a caller's List directly lets them still change it. Fix: this.roles = List.copyOf(roles); Now outside references can't modify the object's internal list.

Good OOP Habits (1)

29 A bank account object with a teller window instead of an open vault
Notes
Keep fields private. Let objects guard their state: account.withdraw(500), not account.balance = -500. Prefer immutability when state needn't change. Keep each class focused on one clear job.

Good OOP Habits (2)

30 A deep tower Animal→Mammal→Dog→SpecialDog vs objects snapped together like Lego
Notes
Program to interfaces: List<String> names = new ArrayList<>(); Prefer composition for has-a relationships over deep inheritance. Don't auto-generate setters — ask: should this change from outside?

The Big Picture

31 A staircase of principles leading up to a trophy labelled 'Clean OOP Design'
Notes
Encapsulation → hide state → control changes → prefer immutability → focused responsibilities → composition. Good OOP isn't about more classes. It's about controlling state, responsibilities and relationships clearly.