Object Oriented Programming With JavaUnit 515 min read
Interfaces, Abstract Classes, Sealed Classes & Wrapper Classes
Unit 5 of Object Oriented Programming With Java covers abstract classes (partial implementations, abstract methods), interfaces (multiple inheritance, default/static methods), sealed classes (restricted hierarchies), and wrapper classes (autoboxing/unboxing) with real-world examples from Nepalese apps like eSewa and Ka
TAKEAWAYS:
- Abstract classes enforce partial implementation (some methods defined, others abstract) and inheritance contracts (subclasses must implement abstract methods).
- Interfaces enable multiple inheritance (a class can implement many interfaces) and define contracts (what methods a class must provide).
- Sealed classes restrict inheritance to specific subclasses, improving API design and preventing misuse.
- Wrapper classes (e.g.,
Integer,Double) convert primitive types to objects, enabling use in collections and generic methods. - Autoboxing/unboxing automatically converts between primitives and their wrapper classes (e.g.,
int↔Integer). - Serialization uses
Serializableinterface andObjectOutputStream/ObjectInputStreamto save/load objects.
1. Abstract Classes: Partial Implementation and Inheritance
Definition and Purpose
An abstract class is a class that cannot be instantiated and may contain:
- Abstract methods (no body, declared with
abstractkeyword). - Concrete methods (fully implemented).
- Fields (instance variables).
- Constructors (to initialize fields).
Why use abstract classes?
- Define a common base for related classes (e.g.,
Shape→Circle,Rectangle). - Enforce method implementation in subclasses (e.g.,
calculateArea()must be defined). - Share common code (e.g., a constructor or utility method).
Syntax
abstract class AbstractClass {
// Abstract method (no body)
abstract void abstractMethod();
// Concrete method (has body)
void concreteMethod() {
System.out.println("Implemented method");
}
}
Example: Traffic Light System
Consider a traffic management system where different traffic lights (e.g., PedestrianLight, VehicleLight) share common behavior but have unique logic.
abstract class TrafficLight {
private String location;
public TrafficLight(String location) {
this.location = location;
}
// Abstract method: must be implemented by subclasses
public abstract void changeState();
// Concrete method: common to all traffic lights
public void displayLocation() {
System.out.println("Traffic light at: " + location);
}
}
class PedestrianLight extends TrafficLight {
public PedestrianLight(String location) {
super(location);
}
@Override
public void changeState() {
System.out.println("Pedestrian light: Walk → Don't Walk");
}
}
Visual: Abstract Class Hierarchy
classDiagram
class TrafficLight {
<<abstract>>
+String location
+TrafficLight(String location)
+abstract changeState()
+displayLocation()
}
class PedestrianLight {
+PedestrianLight(String location)
+changeState()
}
class VehicleLight {
+VehicleLight(String location)
+changeState()
}
TrafficLight <|-- PedestrianLight
TrafficLight <|-- VehicleLightKey Points
- Cannot instantiate:
TrafficLight light = new TrafficLight("Kathmandu");→ Error. - Subclasses must implement abstract methods:
PedestrianLightprovideschangeState(). - Use case: When you want to share code but enforce method implementation.
2. Interfaces: Contracts and Multiple Inheritance
Definition and Purpose
An interface is a pure abstract class (all methods are public abstract by default) that defines a contract for classes to implement. Key features:
- Multiple inheritance: A class can implement many interfaces.
- Default methods: Interfaces can have
defaultmethods (with implementation). - Static methods: Interfaces can have
staticutility methods. - Functional interfaces: Interfaces with one abstract method (used in lambda expressions).
Syntax
interface InterfaceName {
// Abstract method (public abstract by default)
void abstractMethod();
// Default method (has implementation)
default void defaultMethod() {
System.out.println("Default method");
}
// Static method
static void staticMethod() {
System.out.println("Static method");
}
}
Example: Payment Gateway (eSewa-like System)
Suppose we design a payment system where different payment methods (CreditCard, MobileWallet) must implement a common processPayment() method.
interface PaymentMethod {
void processPayment(double amount);
// Default method: common to all payment methods
default void displayReceipt() {
System.out.println("Payment processed successfully");
}
}
class CreditCard implements PaymentMethod {
@Override
public void processPayment(double amount) {
System.out.println("Processing credit card payment: $" + amount);
}
}
class MobileWallet implements PaymentMethod {
@Override
public void processPayment(double amount) {
System.out.println("Processing mobile wallet payment: Rs. " + amount);
}
}
Visual: Interface Implementation
classDiagram
class PaymentMethod {
<<interface>>
+processPayment(double amount)
+default displayReceipt()
}
class CreditCard {
+processPayment(double amount)
}
class MobileWallet {
+processPayment(double amount)
}
PaymentMethod <|-- CreditCard
PaymentMethod <|-- MobileWalletDefault and Static Methods
- Default methods allow adding new methods to interfaces without breaking existing implementations.
- Static methods are utility methods (e.g.,
Collections.sort()).
interface Logger {
void log(String message);
// Default method
default void logWithTimestamp(String message) {
System.out.println("[" + new Date() + "] " + message);
}
// Static method
static void clearLog() {
System.out.println("Log cleared");
}
}
Functional Interfaces and Lambdas
A functional interface has exactly one abstract method. Used with lambdas:
@FunctionalInterface
interface Greeting {
void sayHello(String name);
}
public class Main {
public static void main(String[] args) {
Greeting greet = (name) -> System.out.println("Hello, " + name);
greet.sayHello("Rohan");
}
}
Key Points
- Multiple inheritance: A class can implement
PaymentMethodandNotificationService. - Default methods: Resolve the "diamond problem" (conflicts in multiple inheritance).
- Functional interfaces: Enable lambda expressions and stream APIs.
3. Sealed Classes: Restricted Inheritance
Definition and Purpose
Sealed classes (Java 17+) restrict which classes can extend or implement them. Useful for:
- API design: Prevent misuse (e.g., only specific payment methods allowed).
- Performance: JVM optimizes sealed hierarchies.
- Safety: Ensure only intended subclasses exist.
Syntax
sealed class Shape permits Circle, Rectangle, Triangle {
// ...
}
final class Circle extends Shape { /* ... */ }
non-sealed class Rectangle extends Shape { /* ... */ }
Example: NEPSE Stock Order Types
Suppose NEPSE allows only specific order types (MarketOrder, LimitOrder, StopOrder):
sealed interface Order permits MarketOrder, LimitOrder, StopOrder {
void execute();
}
```figure
{"type":"network","nodes":["Order","MarketOrder","LimitOrder","StopOrder"],"edges":[["Order","MarketOrder"],["Order","LimitOrder"],["Order","StopOrder"]],"directed":true,"caption":"Sealed class hierarchy with permitted subclasses"}
final class MarketOrder implements Order { @Override public void execute() { System.out.println("Executing market order"); } }
non-sealed class LimitOrder implements Order { @Override public void execute() { System.out.println("Executing limit order"); } }
#### **Visual: Sealed Hierarchy**
```mermaid
classDiagram
class Order {
<<sealed>>
+execute()
+final void finalizeOrder()
}
class MarketOrder {
+execute()
}
class LimitOrder {
+execute()
}
class StopOrder {
+execute()
}
Order <|-- MarketOrder
Order <|-- LimitOrder
Order <|-- StopOrder
class SealedPermitted {
<<permitted>>
}
SealedPermitted ..> Order
Key Points
permitsclause: Specifies allowed subclasses/interfaces.finalornon-sealed: Subclasses can be final (no further extension) or non-sealed (can be extended further).- Use case: API design (e.g., Java’s
switchexpression patterns).
4. Wrapper Classes: Primitives to Objects
Definition and Purpose
Wrapper classes convert primitive types (int, double) to objects (Integer, Double). Why?
- Collections:
ArrayList<int>→ Invalid (collections require objects). - Generics:
List<Integer>vs.List<int>. - Null values: Objects can be
null(e.g.,Integer num = null).
Common Wrapper Classes
| Primitive | Wrapper Class | Autoboxing Example | Unboxing Example |
|---|---|---|---|
int |
Integer |
Integer num = 10; |
int x = num; |
double |
Double |
Double d = 3.14; |
double y = d; |
char |
Character |
Character c = 'A'; |
char ch = c; |
boolean |
Boolean |
Boolean flag = true; |
boolean b = flag; |
Example: Prime/Composite String Checker
Write strings to Prime.txt or Composite.txt based on string length:
import java.io.*;
import java.util.Scanner;
public class PrimeCompositeChecker {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter a string: ");
String input = scanner.nextLine();
// Autoboxing: int → Integer
Integer length = input.length();
boolean isPrime = isPrime(length);
try {
FileWriter writer = new FileWriter(isPrime ? "Prime.txt" : "Composite.txt");
writer.write(input);
writer.close();
System.out.println("String written to " + (isPrime ? "Prime.txt" : "Composite.txt"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static boolean isPrime(Integer num) {
if (num <= 1) return false;
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) return false;
}
return true;
}
}
Visual: Autoboxing/Unboxing
flowchart TD
A["Primitive int"] -->|"Autoboxing"| B["Integer Object"]
B -->|"Unboxing"| C["Primitive int"]
D["Primitive double"] -->|"Autoboxing"| E["Double Object"]
E -->|"Unboxing"| F["Primitive double"]Key Points
- Autoboxing: Automatic conversion (e.g.,
int→Integer). - Unboxing: Automatic conversion (e.g.,
Integer→int). - Use case: Collections, generics, and APIs requiring objects.
5. Serialization: Saving Objects to Files
Definition and Purpose
Serialization converts an object’s state into a byte stream for storage/transmission. Used in:
- File I/O: Save objects to disk (e.g., user profiles).
- Networking: Send objects over sockets (e.g., chat messages).
- Distributed systems: Pass objects between services.
Steps to Serialize/Deserialize
- Implement
Serializable:class User implements Serializable { private String name; private int age; // Constructors, getters, setters } - Serialize to File:
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat"))) { User user = new User("Rohan", 25); oos.writeObject(user); // Serialize } - Deserialize from File:
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.dat"))) { User user = (User) ois.readObject(); // Deserialize System.out.println(user.getName()); }
Visual: Serialization Process
sequenceDiagram
participant User as User Object
participant OOS as ObjectOutputStream
participant File as File ("user.dat")
User->>OOS: writeObject()
OOS->>File: Save byte stream
File-->>OIS: Load byte stream
OIS-->>User: readObject()Key Points
Serializableinterface: Marks a class as serializable.transientkeyword: Fields not serialized (e.g., passwords).- Use case: eSewa transaction history, Khalti user data.
In the Real World
eSewa (Nepal):
- Interfaces:
PaymentProcessorinterface definesprocessPayment()forCreditCardPayment,MobilePayment, etc. - Abstract Classes:
Userabstract class enforceslogin()andlogout()inCustomerandAdminsubclasses.
- Interfaces:
Pathao (Ride-Hailing):
- Sealed Classes:
Ordersealed interface restricts order types toRideOrder,DeliveryOrder, etc. - Serialization: Driver locations are serialized to update ride statuses in real-time.
- Sealed Classes:
NTC (Telecom Billing):
- Wrapper Classes:
Integerused for call durations inArrayList<Integer>for billing calculations. - Autoboxing:
doublecall charges are autoboxed toDoublefor storage in databases.
- Wrapper Classes:
NEPSE (Stock Exchange):
- Abstract Classes:
Orderabstract class definesexecute()forMarketOrder,LimitOrder. - Interfaces:
Serializableused to save trade history to files.
- Abstract Classes:
Exam Tip
Abstract vs. Interface:
- Abstract classes can have fields and constructors; interfaces cannot (pre-Java 8).
- Use abstract classes for shared code (e.g.,
TrafficLightconstructor). - Use interfaces for multiple inheritance (e.g.,
PaymentMethod+NotificationService).
Sealed Classes:
- Always mention
permitsclause andfinal/non-sealedmodifiers. - Example: "A sealed class
ShapepermitsCircleandRectangle."
- Always mention
Wrapper Classes:
- Remember autoboxing/unboxing examples (e.g.,
int↔Integer). - Collections require objects:
List<int>→ Error;List<Integer>→ Valid.
- Remember autoboxing/unboxing examples (e.g.,
Serialization:
- Key interfaces:
Serializable,Externalizable. - Methods:
ObjectOutputStream.writeObject(),ObjectInputStream.readObject(). - Exception:
ClassNotFoundExceptionwhen deserializing.
- Key interfaces:
Common Pitfalls:
- Forgetting
implements Serializable→NotSerializableException. - Not handling
IOExceptionin file operations. - Confusing abstract methods (no body) with default methods (has body in interfaces).
- Forgetting
Practice Questions
Code:
abstract class Animal { abstract void makeSound(); } class Dog extends Animal { void makeSound() { System.out.println("Bark"); } }- What is the output of
new Dog().makeSound()? Answer:Bark.
- What is the output of
Design:
- How would you model a
Vehiclehierarchy withCar,Bike, andTruckusing sealed classes?
- How would you model a
Wrapper Classes:
- Write a program to check if a number (input as
String) is a palindrome usingInteger.parseInt()and autoboxing.
- Write a program to check if a number (input as
Summary Table
| Concept | Key Feature | Example |
|---|---|---|
| Abstract Class | Partial implementation, abstract methods |
TrafficLight → PedestrianLight |
| Interface | Multiple inheritance, default methods |
PaymentMethod → CreditCard |
| Sealed Class | Restricted inheritance with permits |
Order → MarketOrder |
| Wrapper Class | Primitives ↔ Objects, autoboxing | int ↔ Integer |
| Serialization | Save/load objects, Serializable |
User object to file |
Based on the TU BITM syllabus for Object Oriented Programming With Java (IT234), unit 5.
Discussion
Loading…