Interface Basics
Interface Definition
An interface defines a contract that implementing classes must follow.
Basic Interface
public interface Drawable {
void draw();
int getArea();
}
// Implement interface
public class Circle implements Drawable {
double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Drawing circle");
}
@Override
public int getArea() {
return (int) (Math.PI * radius * radius);
}
}
Interface Variables
public interface Constants {
// All variables are implicitly public static final
int MAX_SIZE = 100; // public static final
String APP_NAME = "MyApp";
// int count; // COMPILE ERROR - must initialize
}
Interface Methods
public interface Example {
// Implicitly public abstract
void method1(); // public abstract
// All methods are public
// Cannot have private, protected, or default methods (pre-Java 8)
}
Multiple Interface Implementation
public interface Flyable {
void fly();
}
public interface Swimmable {
void swim();
}
public class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Duck flying");
}
@Override
public void swim() {
System.out.println("Duck swimming");
}
}
Interface Inheritance
public interface Shape {
double area();
}
public interface Resizable extends Shape {
void resize(double factor);
}
// Implementing Resizable must implement both area() and resize()
public class Circle implements Resizable {
double radius;
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public void resize(double factor) {
radius *= factor;
}
}
Default Methods
Default Methods (Java 8+)
Default methods provide implementation in interfaces.
Basic Default Method
public interface Greeting {
void greet();
// Default method - has implementation
default void greetWithTime() {
greet();
System.out.println("Have a nice day!");
}
}
public class EnglishGreeting implements Greeting {
@Override
public void greet() {
System.out.println("Hello!");
}
// greetWithTime() inherited automatically
}
EnglishGreeting g = new EnglishGreeting();
g.greetWithTime();
// Output:
// Hello!
// Have a nice day!
Override Default Method
public interface Greeting {
default void greet() {
System.out.println("Default greeting");
}
}
public class CustomGreeting implements Greeting {
@Override
public void greet() {
System.out.println("Custom greeting");
}
}
Multiple Inheritance with Defaults
public interface A {
default void hello() {
System.out.println("A's hello");
}
}
public interface B {
default void hello() {
System.out.println("B's hello");
}
}
// Must resolve conflict
public class C implements A, B {
@Override
public void hello() {
// Must provide implementation
A.super.hello(); // Or B.super.hello()
}
}
Static Methods
public interface MathUtils {
static int square(int n) {
return n * n;
}
static int cube(int n) {
return n * n * n;
}
}
// Call without implementing
int result = MathUtils.square(5); // 25
Practical Example
public interface List<E> {
int size();
boolean isEmpty();
// Default methods
default boolean isNotEmpty() {
return !isEmpty();
}
default void printAll() {
for (E item : this) {
System.out.println(item);
}
}
}
Multiple Inheritance
Multiple Inheritance Through Interfaces
Java supports multiple inheritance via interfaces.
Basic Multiple Inheritance
public interface Flyable {
void fly();
}
public interface Swimmable {
void swim();
}
public interface Runnable {
void run();
}
public class Duck implements Flyable, Swimmable, Runnable {
@Override
public void fly() { System.out.println("Flying"); }
@Override
public void swim() { System.out.println("Swimming"); }
@Override
public void run() { System.out.println("Running"); }
}
Resolving Conflicts
public interface A {
default void hello() { System.out.println("A"); }
default void world() { System.out.println("A world"); }
}
public interface B {
default void hello() { System.out.println("B"); }
}
public class C implements A, B {
@Override
public void hello() {
A.super.hello(); // Explicit choice
}
// world() inherited from A
}
Interface vs Abstract Class for Inheritance
// Abstract class: single inheritance with state
public abstract class Animal {
protected String name;
public abstract void makeSound();
}
// Interface: multiple inheritance, no state
public interface Pet {
void play();
}
public interface Flyable {
void fly();
}
// Dog gets Animal's state + Pet + Flyable capabilities
public class Dog extends Animal implements Pet, Flyable {
public void makeSound() { }
public void play() { }
public void fly() { }
}
Design Pattern: Mixin
public interface Timestamped {
default long getTimestamp() {
return System.currentTimeMillis();
}
}
public interface Logged {
default void log(String message) {
System.out.println("[LOG] " + message);
}
}
public class Service implements Timestamped, Logged {
// Gets both capabilities without inheritance
}
Functional Interfaces
Functional Interfaces
Interfaces with exactly one abstract method, used with lambda expressions.
Basic Functional Interface
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b); // Only one abstract method
// Can have default and static methods
default void print() {
System.out.println("Calculator");
}
}
// Using lambda
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
int sum = add.calculate(5, 3); // 8
int product = multiply.calculate(5, 3); // 15
Built-in Functional Interfaces
// Predicate<T> - takes T, returns boolean
Predicate<String> isEmpty = s -> s.isEmpty();
// Function<T, R> - takes T, returns R
Function<String, Integer> length = s -> s.length();
// Consumer<T> - takes T, returns void
Consumer<String> printer = s -> System.out.println(s);
// Supplier<T> - takes nothing, returns T
Supplier<String> hello = () -> "Hello";
// UnaryOperator<T> - takes T, returns T
UnaryOperator<String> upper = s -> s.toUpperCase();
// BinaryOperator<T> - takes T, T, returns T
BinaryOperator<Integer> add = (a, b) -> a + b;
Method References
// Lambda
Function<String, Integer> length = s -> s.length();
// Method reference
Function<String, Integer> length2 = String::length;
// Both do the same thing
int len = length.apply("hello"); // 5
Practical Examples
// Sort with Comparator
List<String> names = Arrays.asList("Charlie", "Alice", "Bob");
names.sort((a, b) -> a.compareTo(b));
names.sort(String::compareTo); // Method reference
// Filter with Predicate
List<String> filtered = names.stream()
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
// Transform with Function
List<Integer> lengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
@FunctionalInterface Annotation
@FunctionalInterface
public interface MyInterface {
void doSomething();
// Can have default methods
default void helper() { }
// Can have static methods
static void utility() { }
// But only ONE abstract method
// void anotherMethod(); // COMPILE ERROR!
}
Practice Problems
Design a Least Recently Used cache.
Example:
Input: put(1, 1), get(1)
Output: 1
LRU cache operations
Optimal Solution — O(1) time, O(n) space
Use LinkedHashMap or custom implementation.
class LRUCache {
private int capacity;
private Map<Integer, Node> map;
private Node head, tail;
public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<>();
head = new Node(0, 0);
tail = new Node(0, 0);
head.next = tail;
tail.prev = head;
}
}Edge Cases:
- Capacity 1
- Get non-existent
- Update existing
Design a stack that supports getMin() in O(1).
Example:
Input: push(3), push(5), getMin()
Output: 3
Track minimum element
Optimal Solution — O(1) time, O(n) space
Use two stacks or track min with each element.
class MinStack {
private Stack<Integer> stack;
private Stack<Integer> minStack;
public MinStack() {
stack = new Stack<>();
minStack = new Stack<>();
}
public void push(int val) {
stack.push(val);
if (minStack.isEmpty() || val <= minStack.peek())
minStack.push(val);
}
}Edge Cases:
- Pop when empty
- All same values
- Negative values
Design an iterator for a collection.
Example:
Input: hasNext(), next()
Output: element
Standard iterator pattern
Optimal Solution — O(1) time, O(1) space
Implement Iterator interface.
class MyIterator implements Iterator<Integer> {
private List<Integer> list;
private int index = 0;
public MyIterator(List<Integer> list) { this.list = list; }
public boolean hasNext() { return index < list.size(); }
public Integer next() { return list.get(index++); }
}Edge Cases:
- Empty collection
- Single element
- Concurrent modification
Quiz
1. What is a functional interface?
2. Can an interface have constructors?
3. What is a default method?
4. Can a class implement multiple interfaces?
Flashcards
Question
What is the difference between abstract class and interface?
Click to reveal answer
Answer
Abstract class: single inheritance, constructors, state. Interface: multiple inheritance, no constructors, limited state.
Question
What is a functional interface?
Click to reveal answer
Answer
Interface with exactly one abstract method, used with lambda expressions. Annotated with @FunctionalInterface.
Question
What is a default method?
Click to reveal answer
Answer
A method in an interface with a body. Java 8+ feature. Can be overridden by implementing class.
Question
Can interfaces have instance variables?
Click to reveal answer
Answer
No. Interface variables are implicitly public static final (constants only).
Question
What is Interfaces?
Click to reveal answer
Answer
Interfaces is a key concept in Java programming.
Revision Notes
Key Takeaways
- 1.Interfaces define contracts
- 2.Default methods provide implementation
- 3.Functional interfaces enable lambdas
- 4.Multiple interfaces enable multiple inheritance
Interview Tips
- •Know difference between interface and abstract class
- •Understand default method conflicts
- •Use functional interfaces with lambdas
- •Practice interface design patterns
Cheat Sheet
Cheat Sheet
- interface: defines contract
- implements: use interface
- default method: has body (Java 8+)
- static method: belongs to interface
- @FunctionalInterface: one abstract method
- Multiple interfaces: class A implements B, C