OOP Intermediate
Interfaces
Contracts for Behavior
A class can only extend one parent. But a Dog can be both an Animal and a Pet. Interfaces define contracts - a class can implement multiple interfaces, promising to provide certain methods without inheriting implementation.
Basic interface
Define a contract that classes must fulfill.
// Basic Interface Declaration and Implementation
public class BasicInterface {
public static void main(String[] args) {
System.out.println("=== Basic Interface ===\n");
// Cannot instantiate interface!
// Drawable d = new Drawable(); // ERROR
// Create implementing classes
double circleRadius = ;
double rectangleWidth = ;
Circle circle = new Circle(circleRadius);
Rectangle rectangle = new Rectangle(rectangleWidth, 6);
// Call interface methods
circle.draw();
rectangle.draw();
System.out.println("\n=== Interface as Type ===");
// Use interface type for reference
Drawable shape1 = new Circle(3);
Drawable shape2 = new Rectangle(2, 5);
shape1.draw();
shape2.draw();
System.out.println("\n=== Array of Interface Type ===");
Drawable[] shapes = {
new Circle(1),
new Rectangle(2, 3),
new Circle(4)
};
for (Drawable shape : shapes) {
shape.draw();
}
System.out.println("\n=== Interface Characteristics ===");
System.out.println("""
Interface:
- Cannot be instantiated
- Methods are public abstract by default
- Fields are public static final (constants)
- Classes use 'implements' keyword
- Implementing class MUST provide all methods
""");
}
}
// Interface declaration
interface Drawable {
// Method declaration - implicitly public abstract
void draw();
// Can have multiple methods
void resize(double factor);
// Constants - implicitly public static final
int DEFAULT_SIZE = 10;
}
// Class implements interface
class Circle implements Drawable {
private double radius;
Circle(double radius) {
this.radius = radius;
}
// MUST implement all interface methods
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized to radius " + radius);
}
}
class Rectangle implements Drawable {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing rectangle " + width + " x " + height);
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
System.out.println("Rectangle resized to " + width + " x " + height);
}
}
// Basic Interface Declaration and Implementation
public class BasicInterface {
public static void main(String[] args) {
System.out.println("=== Basic Interface ===\n");
// Cannot instantiate interface!
// Drawable d = new Drawable(); // ERROR
// Create implementing classes
double circleRadius = ;
double rectangleWidth = ;
Circle circle = new Circle(circleRadius);
Rectangle rectangle = new Rectangle(rectangleWidth, 6);
// Call interface methods
circle.draw();
rectangle.draw();
System.out.println("\n=== Interface as Type ===");
// Use interface type for reference
Drawable shape1 = new Circle(3);
Drawable shape2 = new Rectangle(2, 5);
shape1.draw();
shape2.draw();
System.out.println("\n=== Array of Interface Type ===");
Drawable[] shapes = {
new Circle(1),
new Rectangle(2, 3),
new Circle(4)
};
for (Drawable shape : shapes) {
shape.draw();
}
System.out.println("\n=== Interface Characteristics ===");
System.out.println("""
Interface:
- Cannot be instantiated
- Methods are public abstract by default
- Fields are public static final (constants)
- Classes use 'implements' keyword
- Implementing class MUST provide all methods
""");
}
}
// Interface declaration
interface Drawable {
// Method declaration - implicitly public abstract
void draw();
// Can have multiple methods
void resize(double factor);
// Constants - implicitly public static final
int DEFAULT_SIZE = 10;
}
// Class implements interface
class Circle implements Drawable {
private double radius;
Circle(double radius) {
this.radius = radius;
}
// MUST implement all interface methods
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized to radius " + radius);
}
}
class Rectangle implements Drawable {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing rectangle " + width + " x " + height);
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
System.out.println("Rectangle resized to " + width + " x " + height);
}
}
// Basic Interface Declaration and Implementation
public class BasicInterface {
public static void main(String[] args) {
System.out.println("=== Basic Interface ===\n");
// Cannot instantiate interface!
// Drawable d = new Drawable(); // ERROR
// Create implementing classes
double circleRadius = ;
double rectangleWidth = ;
Circle circle = new Circle(circleRadius);
Rectangle rectangle = new Rectangle(rectangleWidth, 6);
// Call interface methods
circle.draw();
rectangle.draw();
System.out.println("\n=== Interface as Type ===");
// Use interface type for reference
Drawable shape1 = new Circle(3);
Drawable shape2 = new Rectangle(2, 5);
shape1.draw();
shape2.draw();
System.out.println("\n=== Array of Interface Type ===");
Drawable[] shapes = {
new Circle(1),
new Rectangle(2, 3),
new Circle(4)
};
for (Drawable shape : shapes) {
shape.draw();
}
System.out.println("\n=== Interface Characteristics ===");
System.out.println("""
Interface:
- Cannot be instantiated
- Methods are public abstract by default
- Fields are public static final (constants)
- Classes use 'implements' keyword
- Implementing class MUST provide all methods
""");
}
}
// Interface declaration
interface Drawable {
// Method declaration - implicitly public abstract
void draw();
// Can have multiple methods
void resize(double factor);
// Constants - implicitly public static final
int DEFAULT_SIZE = 10;
}
// Class implements interface
class Circle implements Drawable {
private double radius;
Circle(double radius) {
this.radius = radius;
}
// MUST implement all interface methods
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized to radius " + radius);
}
}
class Rectangle implements Drawable {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing rectangle " + width + " x " + height);
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
System.out.println("Rectangle resized to " + width + " x " + height);
}
}
// Basic Interface Declaration and Implementation
public class BasicInterface {
public static void main(String[] args) {
System.out.println("=== Basic Interface ===\n");
// Cannot instantiate interface!
// Drawable d = new Drawable(); // ERROR
// Create implementing classes
double circleRadius = ;
double rectangleWidth = ;
Circle circle = new Circle(circleRadius);
Rectangle rectangle = new Rectangle(rectangleWidth, 6);
// Call interface methods
circle.draw();
rectangle.draw();
System.out.println("\n=== Interface as Type ===");
// Use interface type for reference
Drawable shape1 = new Circle(3);
Drawable shape2 = new Rectangle(2, 5);
shape1.draw();
shape2.draw();
System.out.println("\n=== Array of Interface Type ===");
Drawable[] shapes = {
new Circle(1),
new Rectangle(2, 3),
new Circle(4)
};
for (Drawable shape : shapes) {
shape.draw();
}
System.out.println("\n=== Interface Characteristics ===");
System.out.println("""
Interface:
- Cannot be instantiated
- Methods are public abstract by default
- Fields are public static final (constants)
- Classes use 'implements' keyword
- Implementing class MUST provide all methods
""");
}
}
// Interface declaration
interface Drawable {
// Method declaration - implicitly public abstract
void draw();
// Can have multiple methods
void resize(double factor);
// Constants - implicitly public static final
int DEFAULT_SIZE = 10;
}
// Class implements interface
class Circle implements Drawable {
private double radius;
Circle(double radius) {
this.radius = radius;
}
// MUST implement all interface methods
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized to radius " + radius);
}
}
class Rectangle implements Drawable {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing rectangle " + width + " x " + height);
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
System.out.println("Rectangle resized to " + width + " x " + height);
}
}
// Basic Interface Declaration and Implementation
public class BasicInterface {
public static void main(String[] args) {
System.out.println("=== Basic Interface ===\n");
// Cannot instantiate interface!
// Drawable d = new Drawable(); // ERROR
// Create implementing classes
double circleRadius = ;
double rectangleWidth = ;
Circle circle = new Circle(circleRadius);
Rectangle rectangle = new Rectangle(rectangleWidth, 6);
// Call interface methods
circle.draw();
rectangle.draw();
System.out.println("\n=== Interface as Type ===");
// Use interface type for reference
Drawable shape1 = new Circle(3);
Drawable shape2 = new Rectangle(2, 5);
shape1.draw();
shape2.draw();
System.out.println("\n=== Array of Interface Type ===");
Drawable[] shapes = {
new Circle(1),
new Rectangle(2, 3),
new Circle(4)
};
for (Drawable shape : shapes) {
shape.draw();
}
System.out.println("\n=== Interface Characteristics ===");
System.out.println("""
Interface:
- Cannot be instantiated
- Methods are public abstract by default
- Fields are public static final (constants)
- Classes use 'implements' keyword
- Implementing class MUST provide all methods
""");
}
}
// Interface declaration
interface Drawable {
// Method declaration - implicitly public abstract
void draw();
// Can have multiple methods
void resize(double factor);
// Constants - implicitly public static final
int DEFAULT_SIZE = 10;
}
// Class implements interface
class Circle implements Drawable {
private double radius;
Circle(double radius) {
this.radius = radius;
}
// MUST implement all interface methods
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized to radius " + radius);
}
}
class Rectangle implements Drawable {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing rectangle " + width + " x " + height);
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
System.out.println("Rectangle resized to " + width + " x " + height);
}
}
// Basic Interface Declaration and Implementation
public class BasicInterface {
public static void main(String[] args) {
System.out.println("=== Basic Interface ===\n");
// Cannot instantiate interface!
// Drawable d = new Drawable(); // ERROR
// Create implementing classes
double circleRadius = ;
double rectangleWidth = ;
Circle circle = new Circle(circleRadius);
Rectangle rectangle = new Rectangle(rectangleWidth, 6);
// Call interface methods
circle.draw();
rectangle.draw();
System.out.println("\n=== Interface as Type ===");
// Use interface type for reference
Drawable shape1 = new Circle(3);
Drawable shape2 = new Rectangle(2, 5);
shape1.draw();
shape2.draw();
System.out.println("\n=== Array of Interface Type ===");
Drawable[] shapes = {
new Circle(1),
new Rectangle(2, 3),
new Circle(4)
};
for (Drawable shape : shapes) {
shape.draw();
}
System.out.println("\n=== Interface Characteristics ===");
System.out.println("""
Interface:
- Cannot be instantiated
- Methods are public abstract by default
- Fields are public static final (constants)
- Classes use 'implements' keyword
- Implementing class MUST provide all methods
""");
}
}
// Interface declaration
interface Drawable {
// Method declaration - implicitly public abstract
void draw();
// Can have multiple methods
void resize(double factor);
// Constants - implicitly public static final
int DEFAULT_SIZE = 10;
}
// Class implements interface
class Circle implements Drawable {
private double radius;
Circle(double radius) {
this.radius = radius;
}
// MUST implement all interface methods
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized to radius " + radius);
}
}
class Rectangle implements Drawable {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing rectangle " + width + " x " + height);
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
System.out.println("Rectangle resized to " + width + " x " + height);
}
}
// Basic Interface Declaration and Implementation
public class BasicInterface {
public static void main(String[] args) {
System.out.println("=== Basic Interface ===\n");
// Cannot instantiate interface!
// Drawable d = new Drawable(); // ERROR
// Create implementing classes
double circleRadius = ;
double rectangleWidth = ;
Circle circle = new Circle(circleRadius);
Rectangle rectangle = new Rectangle(rectangleWidth, 6);
// Call interface methods
circle.draw();
rectangle.draw();
System.out.println("\n=== Interface as Type ===");
// Use interface type for reference
Drawable shape1 = new Circle(3);
Drawable shape2 = new Rectangle(2, 5);
shape1.draw();
shape2.draw();
System.out.println("\n=== Array of Interface Type ===");
Drawable[] shapes = {
new Circle(1),
new Rectangle(2, 3),
new Circle(4)
};
for (Drawable shape : shapes) {
shape.draw();
}
System.out.println("\n=== Interface Characteristics ===");
System.out.println("""
Interface:
- Cannot be instantiated
- Methods are public abstract by default
- Fields are public static final (constants)
- Classes use 'implements' keyword
- Implementing class MUST provide all methods
""");
}
}
// Interface declaration
interface Drawable {
// Method declaration - implicitly public abstract
void draw();
// Can have multiple methods
void resize(double factor);
// Constants - implicitly public static final
int DEFAULT_SIZE = 10;
}
// Class implements interface
class Circle implements Drawable {
private double radius;
Circle(double radius) {
this.radius = radius;
}
// MUST implement all interface methods
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized to radius " + radius);
}
}
class Rectangle implements Drawable {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing rectangle " + width + " x " + height);
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
System.out.println("Rectangle resized to " + width + " x " + height);
}
}
// Basic Interface Declaration and Implementation
public class BasicInterface {
public static void main(String[] args) {
System.out.println("=== Basic Interface ===\n");
// Cannot instantiate interface!
// Drawable d = new Drawable(); // ERROR
// Create implementing classes
double circleRadius = ;
double rectangleWidth = ;
Circle circle = new Circle(circleRadius);
Rectangle rectangle = new Rectangle(rectangleWidth, 6);
// Call interface methods
circle.draw();
rectangle.draw();
System.out.println("\n=== Interface as Type ===");
// Use interface type for reference
Drawable shape1 = new Circle(3);
Drawable shape2 = new Rectangle(2, 5);
shape1.draw();
shape2.draw();
System.out.println("\n=== Array of Interface Type ===");
Drawable[] shapes = {
new Circle(1),
new Rectangle(2, 3),
new Circle(4)
};
for (Drawable shape : shapes) {
shape.draw();
}
System.out.println("\n=== Interface Characteristics ===");
System.out.println("""
Interface:
- Cannot be instantiated
- Methods are public abstract by default
- Fields are public static final (constants)
- Classes use 'implements' keyword
- Implementing class MUST provide all methods
""");
}
}
// Interface declaration
interface Drawable {
// Method declaration - implicitly public abstract
void draw();
// Can have multiple methods
void resize(double factor);
// Constants - implicitly public static final
int DEFAULT_SIZE = 10;
}
// Class implements interface
class Circle implements Drawable {
private double radius;
Circle(double radius) {
this.radius = radius;
}
// MUST implement all interface methods
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized to radius " + radius);
}
}
class Rectangle implements Drawable {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing rectangle " + width + " x " + height);
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
System.out.println("Rectangle resized to " + width + " x " + height);
}
}
// Basic Interface Declaration and Implementation
public class BasicInterface {
public static void main(String[] args) {
System.out.println("=== Basic Interface ===\n");
// Cannot instantiate interface!
// Drawable d = new Drawable(); // ERROR
// Create implementing classes
double circleRadius = ;
double rectangleWidth = ;
Circle circle = new Circle(circleRadius);
Rectangle rectangle = new Rectangle(rectangleWidth, 6);
// Call interface methods
circle.draw();
rectangle.draw();
System.out.println("\n=== Interface as Type ===");
// Use interface type for reference
Drawable shape1 = new Circle(3);
Drawable shape2 = new Rectangle(2, 5);
shape1.draw();
shape2.draw();
System.out.println("\n=== Array of Interface Type ===");
Drawable[] shapes = {
new Circle(1),
new Rectangle(2, 3),
new Circle(4)
};
for (Drawable shape : shapes) {
shape.draw();
}
System.out.println("\n=== Interface Characteristics ===");
System.out.println("""
Interface:
- Cannot be instantiated
- Methods are public abstract by default
- Fields are public static final (constants)
- Classes use 'implements' keyword
- Implementing class MUST provide all methods
""");
}
}
// Interface declaration
interface Drawable {
// Method declaration - implicitly public abstract
void draw();
// Can have multiple methods
void resize(double factor);
// Constants - implicitly public static final
int DEFAULT_SIZE = 10;
}
// Class implements interface
class Circle implements Drawable {
private double radius;
Circle(double radius) {
this.radius = radius;
}
// MUST implement all interface methods
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized to radius " + radius);
}
}
class Rectangle implements Drawable {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing rectangle " + width + " x " + height);
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
System.out.println("Rectangle resized to " + width + " x " + height);
}
}
interface defines method signatures. No implementation (pre-Java 8).
Implement multiple interfaces
A class can implement many interfaces.
// Implementing Multiple Interfaces
public class MultipleInterfaces {
public static void main(String[] args) {
System.out.println("=== Multiple Interfaces ===\n");
// SmartPhone implements multiple interfaces
SmartPhone phone = new SmartPhone("iPhone 15");
System.out.println("--- Using as Camera ---");
phone.takePhoto();
phone.recordVideo();
System.out.println("\n--- Using as Phone ---");
phone.makeCall("555-1234");
phone.sendText("Hello!");
System.out.println("\n--- Using as MediaPlayer ---");
phone.playMusic("Bohemian Rhapsody");
phone.playVideo("YouTube clip");
System.out.println("\n=== Interface References ===");
// Same object, different interface views
Camera cam = phone;
Callable call = phone;
MediaPlayer player = phone;
cam.takePhoto(); // Only Camera methods visible
call.makeCall("555-5678");
player.playMusic("Song");
System.out.println("\n=== Duck Typing with Interfaces ===");
// Different devices, same interfaces
Camera[] cameras = {
new SmartPhone("Pixel"),
new DigitalCamera("Canon"),
};
for (Camera c : cameras) {
c.takePhoto();
}
}
}
// Interface 1
interface Camera {
void takePhoto();
void recordVideo();
}
// Interface 2
interface Callable {
void makeCall(String number);
void sendText(String message);
}
// Interface 3
interface MediaPlayer {
void playMusic(String song);
void playVideo(String video);
}
// Class implementing MULTIPLE interfaces
class SmartPhone implements Camera, Callable, MediaPlayer {
private String model;
SmartPhone(String model) {
this.model = model;
}
// From Camera
@Override
public void takePhoto() {
System.out.println(model + ": 📷 Taking photo");
}
@Override
public void recordVideo() {
System.out.println(model + ": 🎥 Recording video");
}
// From Callable
@Override
public void makeCall(String number) {
System.out.println(model + ": 📞 Calling " + number);
}
@Override
public void sendText(String message) {
System.out.println(model + ": 💬 Sending: " + message);
}
// From MediaPlayer
@Override
public void playMusic(String song) {
System.out.println(model + ": 🎵 Playing " + song);
}
@Override
public void playVideo(String video) {
System.out.println(model + ": ▶️ Playing " + video);
}
}
// Another class implementing just Camera
class DigitalCamera implements Camera {
private String model;
DigitalCamera(String model) {
this.model = model;
}
@Override
public void takePhoto() {
System.out.println(model + " DSLR: 📷 High-quality photo");
}
@Override
public void recordVideo() {
System.out.println(model + " DSLR: 🎥 4K video recording");
}
// No need to implement Callable or MediaPlayer!
}
class X implements A, B, C - must implement all methods from all interfaces.
Interface as type
Use interface type for polymorphism.
// Using Interface as Type
public class InterfaceReference {
public static void main(String[] args) {
System.out.println("=== Interface as Method Parameter ===\n");
Circle circle = new Circle(5);
Rectangle rect = new Rectangle(4, 6);
// Pass different types to same method
printArea(circle);
printArea(rect);
System.out.println("\n=== Interface as Return Type ===");
// Factory method returns interface type
String firstShapeType = ;
Shape shape1 = createShape(firstShapeType, 3);
Shape shape2 = createShape("rectangle", 4);
System.out.println("Created: " + shape1.getName());
System.out.println("Created: " + shape2.getName());
System.out.println("\n=== Collection of Interface Type ===");
Shape[] shapes = {
createShape("circle", 5),
createShape("rectangle", 3),
createShape("circle", 2)
};
double totalArea = calculateTotalArea(shapes);
System.out.println("Total area: " + String.format("%.2f", totalArea));
System.out.println("\n=== Interface Extends Interface ===");
// 3DShape extends Shape
Sphere sphere = new Sphere(4);
System.out.println("Sphere:");
System.out.println(" Area: " + String.format("%.2f", sphere.getArea()));
System.out.println(" Volume: " + String.format("%.2f", sphere.getVolume()));
// Can use as Shape too!
printArea(sphere);
}
// Method with interface parameter
static void printArea(Shape shape) {
System.out.println(shape.getName() + " area: " +
String.format("%.2f", shape.getArea()));
}
// Method with interface return type
static Shape createShape(String type, double size) {
return switch(type.toLowerCase()) {
case "circle" -> new Circle(size);
case "rectangle" -> new Rectangle(size, size);
default -> throw new IllegalArgumentException("Unknown shape: " + type);
};
}
// Method processing array of interfaces
static double calculateTotalArea(Shape[] shapes) {
double total = 0;
for (Shape s : shapes) {
total += s.getArea();
}
return total;
}
}
// Base interface
interface Shape {
double getArea();
String getName();
}
// Interface extending interface
interface Shape3D extends Shape {
double getVolume();
// Also inherits getArea() and getName()!
}
class Circle implements Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public String getName() {
return "Circle (r=" + radius + ")";
}
}
class Rectangle implements Shape {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double getArea() {
return width * height;
}
@Override
public String getName() {
return "Rectangle (" + width + "x" + height + ")";
}
}
// Implements extended interface
class Sphere implements Shape3D {
private double radius;
Sphere(double radius) {
this.radius = radius;
}
// From Shape (inherited by Shape3D)
@Override
public double getArea() {
return 4 * Math.PI * radius * radius; // Surface area
}
@Override
public String getName() {
return "Sphere (r=" + radius + ")";
}
// From Shape3D
@Override
public double getVolume() {
return (4.0 / 3.0) * Math.PI * radius * radius * radius;
}
}
// Using Interface as Type
public class InterfaceReference {
public static void main(String[] args) {
System.out.println("=== Interface as Method Parameter ===\n");
Circle circle = new Circle(5);
Rectangle rect = new Rectangle(4, 6);
// Pass different types to same method
printArea(circle);
printArea(rect);
System.out.println("\n=== Interface as Return Type ===");
// Factory method returns interface type
String firstShapeType = ;
Shape shape1 = createShape(firstShapeType, 3);
Shape shape2 = createShape("rectangle", 4);
System.out.println("Created: " + shape1.getName());
System.out.println("Created: " + shape2.getName());
System.out.println("\n=== Collection of Interface Type ===");
Shape[] shapes = {
createShape("circle", 5),
createShape("rectangle", 3),
createShape("circle", 2)
};
double totalArea = calculateTotalArea(shapes);
System.out.println("Total area: " + String.format("%.2f", totalArea));
System.out.println("\n=== Interface Extends Interface ===");
// 3DShape extends Shape
Sphere sphere = new Sphere(4);
System.out.println("Sphere:");
System.out.println(" Area: " + String.format("%.2f", sphere.getArea()));
System.out.println(" Volume: " + String.format("%.2f", sphere.getVolume()));
// Can use as Shape too!
printArea(sphere);
}
// Method with interface parameter
static void printArea(Shape shape) {
System.out.println(shape.getName() + " area: " +
String.format("%.2f", shape.getArea()));
}
// Method with interface return type
static Shape createShape(String type, double size) {
return switch(type.toLowerCase()) {
case "circle" -> new Circle(size);
case "rectangle" -> new Rectangle(size, size);
default -> throw new IllegalArgumentException("Unknown shape: " + type);
};
}
// Method processing array of interfaces
static double calculateTotalArea(Shape[] shapes) {
double total = 0;
for (Shape s : shapes) {
total += s.getArea();
}
return total;
}
}
// Base interface
interface Shape {
double getArea();
String getName();
}
// Interface extending interface
interface Shape3D extends Shape {
double getVolume();
// Also inherits getArea() and getName()!
}
class Circle implements Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public String getName() {
return "Circle (r=" + radius + ")";
}
}
class Rectangle implements Shape {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double getArea() {
return width * height;
}
@Override
public String getName() {
return "Rectangle (" + width + "x" + height + ")";
}
}
// Implements extended interface
class Sphere implements Shape3D {
private double radius;
Sphere(double radius) {
this.radius = radius;
}
// From Shape (inherited by Shape3D)
@Override
public double getArea() {
return 4 * Math.PI * radius * radius; // Surface area
}
@Override
public String getName() {
return "Sphere (r=" + radius + ")";
}
// From Shape3D
@Override
public double getVolume() {
return (4.0 / 3.0) * Math.PI * radius * radius * radius;
}
}
Drawable d = new Circle() - variable type is interface, object is implementing class.
Default methods
Interfaces can provide default implementations (Java 8+).
// Default Methods (Java 8+)
public class DefaultMethods {
public static void main(String[] args) {
System.out.println("=== Default Methods in Interfaces ===\n");
// BasicPrinter uses default log()
BasicPrinter basic = new BasicPrinter();
basic.print("Hello");
basic.log("Starting print job");
System.out.println("\n=== Overriding Default Method ===");
// AdvancedPrinter overrides log()
AdvancedPrinter advanced = new AdvancedPrinter();
advanced.print("Document");
advanced.log("Print initiated");
System.out.println("\n=== Static Methods in Interface ===");
// Call static method on interface
String version = Printable.getVersion();
System.out.println("Printable version: " + version);
System.out.println("\n=== Multiple Interfaces with Same Default ===");
MultiDevice device = new MultiDevice();
device.connect();
System.out.println("\n=== Why Default Methods? ===");
System.out.println("""
Before Java 8:
- Adding method to interface broke all implementations
- Every class needed updating
With default methods:
- Add new methods with default implementation
- Existing classes still work
- Optional override for custom behavior
Real examples:
- List.sort() - added in Java 8
- Collection.stream() - added in Java 8
""");
}
}
// Interface with default method
interface Printable {
// Abstract method - must implement
void print(String content);
// Default method - optional to override
default void log(String message) {
System.out.println("[LOG] " + message);
}
// Another default method
default void preview() {
System.out.println("Showing preview...");
}
// Static method in interface
static String getVersion() {
return "1.0";
}
}
// Uses default implementation
class BasicPrinter implements Printable {
@Override
public void print(String content) {
System.out.println("Printing: " + content);
}
// Does NOT override log() - uses default
// Does NOT override preview() - uses default
}
// Overrides default method
class AdvancedPrinter implements Printable {
@Override
public void print(String content) {
System.out.println("Advanced printing: " + content);
}
@Override
public void log(String message) {
System.out.println("[ADVANCED LOG] " +
java.time.LocalTime.now() + " - " + message);
}
}
// Two interfaces with same default method
interface USB {
default void connect() {
System.out.println("USB connecting...");
}
}
interface Bluetooth {
default void connect() {
System.out.println("Bluetooth connecting...");
}
}
// Must resolve conflict
class MultiDevice implements USB, Bluetooth {
@Override
public void connect() {
System.out.println("Multi-device connecting:");
USB.super.connect();
Bluetooth.super.connect();
}
}
default void method() { } - provides implementation that classes can inherit or override.
Functional interfaces
Interfaces with exactly one abstract method work with lambdas.
// Functional Interfaces and Lambdas
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
System.out.println("=== Functional Interface ===\n");
// Traditional: Anonymous inner class
Calculator add1 = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
System.out.println("Anonymous class: 5 + 3 = " + add1.calculate(5, 3));
// Modern: Lambda expression
Calculator add2 = (a, b) -> a + b;
System.out.println("Lambda: 5 + 3 = " + add2.calculate(5, 3));
System.out.println("\n=== Multiple Operations ===");
// Different operations, same interface
Calculator subtract = (a, b) -> a - b;
Calculator multiply = (a, b) -> a * b;
Calculator divide = (a, b) -> a / b;
Calculator max = (a, b) -> a > b ? a : b;
int x = ;
int y = ;
System.out.println(x + " + " + y + " = " + add2.calculate(x, y));
System.out.println(x + " - " + y + " = " + subtract.calculate(x, y));
System.out.println(x + " * " + y + " = " + multiply.calculate(x, y));
System.out.println(x + " / " + y + " = " + divide.calculate(x, y));
System.out.println("max(" + x + ", " + y + ") = " + max.calculate(x, y));
System.out.println("\n=== Passing Lambda to Method ===");
// Pass behavior as parameter
applyOperation("Addition", 7, 3, (a, b) -> a + b);
applyOperation("Power", 2, 8, (a, b) -> (int) Math.pow(a, b));
System.out.println("\n=== Lambda Variations ===");
// Single parameter
Greeter hello = name -> "Hello, " + name + "!";
System.out.println(hello.greet("World"));
// Multi-line body
Greeter formal = name -> {
String title = "Dear " + name;
return title + ", welcome!";
};
System.out.println(formal.greet("Guest"));
// No parameters
MessageSupplier supplier = () -> "Generated message at " + System.currentTimeMillis();
System.out.println(supplier.get());
System.out.println("\n=== @FunctionalInterface ===");
System.out.println("""
@FunctionalInterface annotation:
- Documents intent
- Compiler enforces single abstract method
- Enables lambda usage
Common built-in functional interfaces:
- Runnable: () -> void
- Comparator<T>: (T, T) -> int
- Consumer<T>: (T) -> void
- Supplier<T>: () -> T
- Function<T, R>: (T) -> R
- Predicate<T>: (T) -> boolean
""");
}
// Method accepting functional interface
static void applyOperation(String name, int a, int b, Calculator calc) {
int result = calc.calculate(a, b);
System.out.println(name + ": " + a + " op " + b + " = " + result);
}
}
// Functional interface - exactly ONE abstract method
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
// Default methods allowed!
default void printResult(int a, int b) {
System.out.println("Result: " + calculate(a, b));
}
}
// Another functional interface
@FunctionalInterface
interface Greeter {
String greet(String name);
}
@FunctionalInterface
interface MessageSupplier {
String get();
}
// Functional Interfaces and Lambdas
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
System.out.println("=== Functional Interface ===\n");
// Traditional: Anonymous inner class
Calculator add1 = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
System.out.println("Anonymous class: 5 + 3 = " + add1.calculate(5, 3));
// Modern: Lambda expression
Calculator add2 = (a, b) -> a + b;
System.out.println("Lambda: 5 + 3 = " + add2.calculate(5, 3));
System.out.println("\n=== Multiple Operations ===");
// Different operations, same interface
Calculator subtract = (a, b) -> a - b;
Calculator multiply = (a, b) -> a * b;
Calculator divide = (a, b) -> a / b;
Calculator max = (a, b) -> a > b ? a : b;
int x = ;
int y = ;
System.out.println(x + " + " + y + " = " + add2.calculate(x, y));
System.out.println(x + " - " + y + " = " + subtract.calculate(x, y));
System.out.println(x + " * " + y + " = " + multiply.calculate(x, y));
System.out.println(x + " / " + y + " = " + divide.calculate(x, y));
System.out.println("max(" + x + ", " + y + ") = " + max.calculate(x, y));
System.out.println("\n=== Passing Lambda to Method ===");
// Pass behavior as parameter
applyOperation("Addition", 7, 3, (a, b) -> a + b);
applyOperation("Power", 2, 8, (a, b) -> (int) Math.pow(a, b));
System.out.println("\n=== Lambda Variations ===");
// Single parameter
Greeter hello = name -> "Hello, " + name + "!";
System.out.println(hello.greet("World"));
// Multi-line body
Greeter formal = name -> {
String title = "Dear " + name;
return title + ", welcome!";
};
System.out.println(formal.greet("Guest"));
// No parameters
MessageSupplier supplier = () -> "Generated message at " + System.currentTimeMillis();
System.out.println(supplier.get());
System.out.println("\n=== @FunctionalInterface ===");
System.out.println("""
@FunctionalInterface annotation:
- Documents intent
- Compiler enforces single abstract method
- Enables lambda usage
Common built-in functional interfaces:
- Runnable: () -> void
- Comparator<T>: (T, T) -> int
- Consumer<T>: (T) -> void
- Supplier<T>: () -> T
- Function<T, R>: (T) -> R
- Predicate<T>: (T) -> boolean
""");
}
// Method accepting functional interface
static void applyOperation(String name, int a, int b, Calculator calc) {
int result = calc.calculate(a, b);
System.out.println(name + ": " + a + " op " + b + " = " + result);
}
}
// Functional interface - exactly ONE abstract method
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
// Default methods allowed!
default void printResult(int a, int b) {
System.out.println("Result: " + calculate(a, b));
}
}
// Another functional interface
@FunctionalInterface
interface Greeter {
String greet(String name);
}
@FunctionalInterface
interface MessageSupplier {
String get();
}
// Functional Interfaces and Lambdas
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
System.out.println("=== Functional Interface ===\n");
// Traditional: Anonymous inner class
Calculator add1 = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
System.out.println("Anonymous class: 5 + 3 = " + add1.calculate(5, 3));
// Modern: Lambda expression
Calculator add2 = (a, b) -> a + b;
System.out.println("Lambda: 5 + 3 = " + add2.calculate(5, 3));
System.out.println("\n=== Multiple Operations ===");
// Different operations, same interface
Calculator subtract = (a, b) -> a - b;
Calculator multiply = (a, b) -> a * b;
Calculator divide = (a, b) -> a / b;
Calculator max = (a, b) -> a > b ? a : b;
int x = ;
int y = ;
System.out.println(x + " + " + y + " = " + add2.calculate(x, y));
System.out.println(x + " - " + y + " = " + subtract.calculate(x, y));
System.out.println(x + " * " + y + " = " + multiply.calculate(x, y));
System.out.println(x + " / " + y + " = " + divide.calculate(x, y));
System.out.println("max(" + x + ", " + y + ") = " + max.calculate(x, y));
System.out.println("\n=== Passing Lambda to Method ===");
// Pass behavior as parameter
applyOperation("Addition", 7, 3, (a, b) -> a + b);
applyOperation("Power", 2, 8, (a, b) -> (int) Math.pow(a, b));
System.out.println("\n=== Lambda Variations ===");
// Single parameter
Greeter hello = name -> "Hello, " + name + "!";
System.out.println(hello.greet("World"));
// Multi-line body
Greeter formal = name -> {
String title = "Dear " + name;
return title + ", welcome!";
};
System.out.println(formal.greet("Guest"));
// No parameters
MessageSupplier supplier = () -> "Generated message at " + System.currentTimeMillis();
System.out.println(supplier.get());
System.out.println("\n=== @FunctionalInterface ===");
System.out.println("""
@FunctionalInterface annotation:
- Documents intent
- Compiler enforces single abstract method
- Enables lambda usage
Common built-in functional interfaces:
- Runnable: () -> void
- Comparator<T>: (T, T) -> int
- Consumer<T>: (T) -> void
- Supplier<T>: () -> T
- Function<T, R>: (T) -> R
- Predicate<T>: (T) -> boolean
""");
}
// Method accepting functional interface
static void applyOperation(String name, int a, int b, Calculator calc) {
int result = calc.calculate(a, b);
System.out.println(name + ": " + a + " op " + b + " = " + result);
}
}
// Functional interface - exactly ONE abstract method
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
// Default methods allowed!
default void printResult(int a, int b) {
System.out.println("Result: " + calculate(a, b));
}
}
// Another functional interface
@FunctionalInterface
interface Greeter {
String greet(String name);
}
@FunctionalInterface
interface MessageSupplier {
String get();
}
// Functional Interfaces and Lambdas
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
System.out.println("=== Functional Interface ===\n");
// Traditional: Anonymous inner class
Calculator add1 = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
System.out.println("Anonymous class: 5 + 3 = " + add1.calculate(5, 3));
// Modern: Lambda expression
Calculator add2 = (a, b) -> a + b;
System.out.println("Lambda: 5 + 3 = " + add2.calculate(5, 3));
System.out.println("\n=== Multiple Operations ===");
// Different operations, same interface
Calculator subtract = (a, b) -> a - b;
Calculator multiply = (a, b) -> a * b;
Calculator divide = (a, b) -> a / b;
Calculator max = (a, b) -> a > b ? a : b;
int x = ;
int y = ;
System.out.println(x + " + " + y + " = " + add2.calculate(x, y));
System.out.println(x + " - " + y + " = " + subtract.calculate(x, y));
System.out.println(x + " * " + y + " = " + multiply.calculate(x, y));
System.out.println(x + " / " + y + " = " + divide.calculate(x, y));
System.out.println("max(" + x + ", " + y + ") = " + max.calculate(x, y));
System.out.println("\n=== Passing Lambda to Method ===");
// Pass behavior as parameter
applyOperation("Addition", 7, 3, (a, b) -> a + b);
applyOperation("Power", 2, 8, (a, b) -> (int) Math.pow(a, b));
System.out.println("\n=== Lambda Variations ===");
// Single parameter
Greeter hello = name -> "Hello, " + name + "!";
System.out.println(hello.greet("World"));
// Multi-line body
Greeter formal = name -> {
String title = "Dear " + name;
return title + ", welcome!";
};
System.out.println(formal.greet("Guest"));
// No parameters
MessageSupplier supplier = () -> "Generated message at " + System.currentTimeMillis();
System.out.println(supplier.get());
System.out.println("\n=== @FunctionalInterface ===");
System.out.println("""
@FunctionalInterface annotation:
- Documents intent
- Compiler enforces single abstract method
- Enables lambda usage
Common built-in functional interfaces:
- Runnable: () -> void
- Comparator<T>: (T, T) -> int
- Consumer<T>: (T) -> void
- Supplier<T>: () -> T
- Function<T, R>: (T) -> R
- Predicate<T>: (T) -> boolean
""");
}
// Method accepting functional interface
static void applyOperation(String name, int a, int b, Calculator calc) {
int result = calc.calculate(a, b);
System.out.println(name + ": " + a + " op " + b + " = " + result);
}
}
// Functional interface - exactly ONE abstract method
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
// Default methods allowed!
default void printResult(int a, int b) {
System.out.println("Result: " + calculate(a, b));
}
}
// Another functional interface
@FunctionalInterface
interface Greeter {
String greet(String name);
}
@FunctionalInterface
interface MessageSupplier {
String get();
}
@FunctionalInterface ensures single abstract method. Use with lambdas.
Exercise: Practical.java
Build a plugin system using interfaces