Week 3 - OOP Pillars & Advanced Concepts
Class 7 - Recording
▶ Watch VideoInheritance in Java
Inheritance allows a subclass to acquire the properties and behaviors of a superclass. It promotes code reusability and method overriding.
Example:
class Animal {
void sound() {
System.out.println("Animals make sounds");
}
}
class Dog extends Animal {
void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Dog d = new Dog();
d.sound(); // Output: Dog barks
}
}
Important Points:
- Java does not support multiple inheritance with classes.
- All classes inherit from the Object class.
- Use
superto access parent methods or constructors.
Related Exceptions:
// ClassCastException example
Animal a = new Animal();
Dog d = (Dog) a; // Throws ClassCastException
Polymorphism in Java
Polymorphism means one interface, many implementations. It allows methods to behave differently based on the object.
1. Compile-time Polymorphism (Method Overloading)
class MathOps {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
}
2. Runtime Polymorphism (Method Overriding)
class Bird {
void fly() {
System.out.println("Bird is flying");
}
}
class Eagle extends Bird {
void fly() {
System.out.println("Eagle flies high");
}
}
public class Test {
public static void main(String[] args) {
Bird b = new Eagle();
b.fly(); // Output: Eagle flies high
}
}
Important Points:
- Method overloading is resolved at compile-time.
- Method overriding is resolved at runtime.
- Overridden methods must have the same signature.
- Return type can be covariant (subtype allowed).
Related Exceptions:
// Wrong downcasting -> ClassCastException
Bird b = new Bird();
Eagle e = (Eagle) b; // Throws ClassCastException
Encapsulation in Java
Encapsulation wraps data (variables) and methods within a class and protects them from unauthorized access using private access modifiers.
Example:
class Student {
private String name;
private int age;
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
public int getAge() { return age; }
public void setAge(int age) {
if (age > 0) {
this.age = age;
} else {
System.out.println("Invalid age");
}
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student();
s.setName("John");
s.setAge(20);
System.out.println(s.getName());
System.out.println(s.getAge());
}
}
Important Points:
- Use private variables and public getters/setters.
- Encapsulation protects data and enables validation.
- Improves maintainability and flexibility.
Related Exceptions:
// Custom exception in setter
public void setAge(int age) {
if (age <= 0) {
throw new IllegalArgumentException("Age must be positive");
}
this.age = age;
}
Class 8 - Recording
▶ Watch VideoAbstract Classes in Java
Abstract classes are classes that cannot be instantiated directly. They serve as blueprints for other classes and can contain both abstract and concrete methods.
What is an Abstract Class?
An abstract class is declared with the abstract keyword. It can have:
- Abstract methods (without body)
- Concrete methods (with body)
- Instance variables
- Constructors
Example: Basic Abstract Class
abstract class Vehicle {
// abstract method (no body)
abstract void start();
abstract void stop();
// concrete method
void honk() {
System.out.println("Beep Beep!");
}
}
class Car extends Vehicle {
@Override
void start() {
System.out.println("Car engine started");
}
@Override
void stop() {
System.out.println("Car stopped");
}
}
public class Main {
public static void main(String[] args) {
// Vehicle v = new Vehicle(); // ❌ Compile Error: Cannot instantiate abstract class
Car car = new Car();
car.start(); // Output: Car engine started
car.honk(); // Output: Beep Beep!
car.stop(); // Output: Car stopped
}
}
Real-World Use Case
Imagine a payment system. The Payment class is abstract because different payment methods work differently:
abstract class Payment {
abstract void processPayment(double amount);
abstract void refund();
void printReceipt() {
System.out.println("--- Receipt ---");
}
}
class CreditCardPayment extends Payment {
@Override
void processPayment(double amount) {
System.out.println("Processing credit card payment: $" + amount);
}
@Override
void refund() {
System.out.println("Refunding to credit card");
}
}
class UPIPayment extends Payment {
@Override
void processPayment(double amount) {
System.out.println("Processing UPI payment: $" + amount);
}
@Override
void refund() {
System.out.println("Refunding UPI amount");
}
}
Key Points:
- Cannot create instance of abstract class
- Subclass MUST override all abstract methods
- A subclass can also be abstract (doesn't need to implement all methods)
- Abstract classes can have constructors (for initialization)
- Use abstract classes for "IS-A" relationships
Abstract Class vs Concrete Class
| Feature | Abstract Class | Concrete Class |
|---|---|---|
| Can Instantiate | No | Yes |
| Can have abstract methods | Yes | No |
| Can have concrete methods | Yes | Yes |
| Constructor | Yes | Yes |
Interfaces in Java
Interfaces are contracts that define what methods a class must implement. They promote loose coupling and multiple inheritance of behavior.
What is an Interface?
An interface is a blueprint of a class. It contains only abstract methods and constants (before Java 8). From Java 8 onwards, interfaces can have default methods and static methods.
Example: Basic Interface
interface Animal {
void eat();
void sleep();
}
class Dog implements Animal {
@Override
public void eat() {
System.out.println("Dog is eating");
}
@Override
public void sleep() {
System.out.println("Dog is sleeping");
}
}
public class Main {
public static void main(String[] args) {
// Animal a = new Animal(); // ❌ Compile Error: Cannot instantiate interface
Dog dog = new Dog();
dog.eat(); // Output: Dog is eating
dog.sleep(); // Output: Dog is sleeping
}
}
Real-World Use Case: Multiple Implementations
interface Drawable {
void draw();
}
class Circle implements Drawable {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
class Rectangle implements Drawable {
@Override
public void draw() {
System.out.println("Drawing a rectangle");
}
}
public class Main {
public static void main(String[] args) {
Drawable c = new Circle();
Drawable r = new Rectangle();
c.draw(); // Output: Drawing a circle
r.draw(); // Output: Drawing a rectangle
}
}
Multiple Inheritance with Interfaces
A class can implement multiple interfaces, allowing multiple inheritance:
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Duck is flying");
}
@Override
public void swim() {
System.out.println("Duck is swimming");
}
}
public class Main {
public static void main(String[] args) {
Duck duck = new Duck();
duck.fly(); // Output: Duck is flying
duck.swim(); // Output: Duck is swimming
}
}
Default Methods (Java 8+)
Interfaces can now have concrete methods with the default keyword:
interface Logger {
void log(String msg);
default void logInfo(String msg) {
System.out.println("[INFO] " + msg);
}
}
class ConsoleLogger implements Logger {
@Override
public void log(String msg) {
System.out.println("Console: " + msg);
}
}
public class Main {
public static void main(String[] args) {
Logger logger = new ConsoleLogger();
logger.log("Hello"); // Output: Console: Hello
logger.logInfo("Info msg"); // Output: [INFO] Info msg
}
}
Static Methods in Interfaces (Java 8+)
interface MathOps {
static int add(int a, int b) {
return a + b;
}
static int multiply(int a, int b) {
return a * b;
}
}
public class Main {
public static void main(String[] args) {
System.out.println(MathOps.add(5, 3)); // Output: 8
System.out.println(MathOps.multiply(5, 3)); // Output: 15
}
}
Key Points:
- A class can implement multiple interfaces
- An interface can extend other interfaces
- All methods in interface are public and abstract (by default)
- From Java 8: interfaces can have default and static methods
- Use interfaces for "HAS-A" or "CAN-DO" relationships
- Interfaces support loose coupling and flexibility
Abstract Class vs Interface
| Feature | Abstract Class | Interface |
|---|---|---|
| Multiple Inheritance | No (single) | Yes (multiple) |
| Access Modifiers | public, private, protected | public (implicit) |
| Constructor | Yes | No |
| Instance Variables | Yes (any type) | Only constants |
| When to Use | IS-A relationship | CAN-DO relationship |
When to Use What?
- Abstract Class: When classes share common code and state
- Interface: When defining behavior contract for unrelated classes
- Both: Abstract class can implement multiple interfaces