Java Oops
Modern and Practical Oops
On this page
- Phase 4: Modern Practical OOP
- Interface = A Contract
- Abstract Methods
- Default Methods (Java 8)
- Why Default Methods Exist
- Static Methods in Interfaces
- Private Methods (Java 9)
- Interface Constants
- Multiple Interfaces
- Default Method Conflict
- Functional Interfaces
- Built-in Functional Interfaces
- Enum = Fixed Set of Options
- Why Enums Beat Strings
- Enums with Fields & Methods
- Handy Enum Methods
- Enums Under the Hood
- Records: Data With Less Code
- Using a Record
- Records Are Immutable (Shallowly)
- Compact Constructor
- Record Rules
- Sealed Classes: Controlled Inheritance
- Permitted Subclass Choices
- Why Sealed + Pattern Matching
- Immutable Objects
- Making a Class Immutable
- Defensive Copies
- Good OOP Habits (1)
- Good OOP Habits (2)
- The Big Picture
Phase 4: Modern Practical OOP
01
Notes
Five topics in this phase:
• Interfaces (deep dive)
• Enums, Records, Sealed Classes
• Immutable objects & good design habits
Interface = A Contract
02
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
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
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
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
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
Notes
Internal helpers shared by methods inside the interface.
Example: generateReceipt() calls private logTransaction().
Outside code cannot call it: upi.logTransaction() ✗
Interface Constants
08
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.