LLD
Machine Coding
Interview Course
Java โ€ข Interview Prep
๐Ÿงฑ OOP Fundamentals/

Interfaces: The Contract

Lesson 6 of 8

Interfaces: The Contract


What is it? (The Analogy)

Think about a USB port on your computer. It does not care WHAT you plug into it -- a mouse, a keyboard, a flash drive, a phone charger, an external hard drive. It just says: "If you follow the USB specification (have the right shape, the right electrical signals, the right data protocol), you can plug in and we will work together." The USB port defines a contract. Any device that follows the contract is welcome.

In Java, an interface is exactly that -- a contract. It says: "If you \implement\ me, you PROMISE to provide these methods." That is it. The interface does not care what class you are, what you inherit from, or how you implement the methods. It just demands that you CAN do certain things. A \Sortable\ interface says "you must have a \compareTo()\ method." A \Printable\ interface says "you must have a \print()\ method." WHO you are does not matter. WHAT you can do is everything.

And here is the magic: while Java only allows you to extend ONE class (single inheritance), you can implement AS MANY interfaces as you want. A \SmartPhone\ class can implement \Camera\, \GPS\, \MediaPlayer\, \PhoneCall\, and \WebBrowser\ all at once. Interfaces are Java's answer to the problem of multiple inheritance.


Why do we need it?

Imagine you are building a system where many different types of objects need to be saved to a database. Without interfaces:

java
1// WITHOUT interfaces -- tightly coupled to specific types
2public class DatabaseSaver {
3    public void saveUser(User user) {
4        String data = "User:" + user.getName() + "," + user.getEmail();
5        writeToDatabase(data);
6    }
7
8    public void saveProduct(Product product) {
9        String data = "Product:" + product.getName() + "," + product.getPrice();
10        writeToDatabase(data);
11    }
12
13    public void saveOrder(Order order) {
14        String data = "Order:" + order.getId() + "," + order.getTotal();
15        writeToDatabase(data);
16    }
17
18    // 50 more saveXxx methods for 50 types... this is insane!
19    // Each new type requires modifying this class!
20}

With interfaces:

java
1// The interface -- a contract that says "I can be saved"
2public interface Saveable {
3    String toSaveFormat();
4}
5
6// Now the saver works with ANY type that implements Saveable
7public class DatabaseSaver {
8    public void save(Saveable item) {
9        String data = item.toSaveFormat();  // Polymorphism via interface!
10        writeToDatabase(data);
11    }
12    // ONE method. Works with ALL types. Current AND future. Done.
13}
14
15// Any class can "sign the contract"
16public class User implements Saveable {
17    @Override
18    public String toSaveFormat() {
19        return "User:" + name + "," + email;
20    }
21}

How it works -- Step by Step

  1. Define an interface -- Use the \interface\ keyword. List method signatures (no bodies, pre-Java 8).
  2. A class implements the interface -- Use \implements InterfaceName\. The class MUST provide bodies for ALL interface methods.
  3. Multiple interfaces are allowed -- \class Dog implements Runnable, Comparable<Dog>, Serializable\.
  4. Use the interface as a type -- Declare variables, parameters, and collections as the interface type for maximum flexibility.
  5. Default methods (Java 8+) -- Interfaces CAN have methods with bodies using the \default\ keyword.
  6. Static methods -- Interfaces can also have static utility methods.
  7. Functional interfaces -- An interface with exactly ONE abstract method can be used with lambda expressions.

Let's Build It Together

Let's build a media player system where totally different objects share abilities through interfaces!

java
1// Interface #1: Can be played
2public interface Playable {
3    void play();
4    void pause();
5    void stop();
6    int getDurationInSeconds();
7}
java
1// Interface #2: Can be rated by users
2public interface Rateable {
3    void addRating(int stars);  // 1-5
4    double getAverageRating();
5    int getTotalRatings();
6}
java
1// Interface #3: Can be downloaded
2public interface Downloadable {
3    void download(String path);
4    double getFileSizeMB();
5
6    // DEFAULT METHOD -- has a body! (Java 8+)
7    // Implementing classes get this for free, but can override it.
8    default String getDownloadInfo() {
9        return String.format("%.1f MB", getFileSizeMB());
10    }
11}
java
1// Song implements ALL THREE interfaces!
2// It IS Playable, IS Rateable, and IS Downloadable.
3public class Song implements Playable, Rateable, Downloadable {
4    private String title;
5    private String artist;
6    private int durationSeconds;
7    private double fileSizeMB;
8    private List<Integer> ratings;
9
10    public Song(String title, String artist, int durationSeconds, double fileSizeMB) {
11        this.title = title;
12        this.artist = artist;
13        this.durationSeconds = durationSeconds;
14        this.fileSizeMB = fileSizeMB;
15        this.ratings = new ArrayList<>();
16    }
17
18    // ===== Playable implementation =====
19    @Override
20    public void play() {
21        System.out.println("Now playing: "" + title + "" by " + artist);
22    }
23
24    @Override
25    public void pause() {
26        System.out.println("Paused: "" + title + """);
27    }
28
29    @Override
30    public void stop() {
31        System.out.println("Stopped: "" + title + """);
32    }
33
34    @Override
35    public int getDurationInSeconds() {
36        return durationSeconds;
37    }
38
39    // ===== Rateable implementation =====
40    @Override
41    public void addRating(int stars) {
42        if (stars < 1 || stars > 5) {
43            throw new IllegalArgumentException("Rating must be 1-5!");
44        }
45        ratings.add(stars);
46    }
47
48    @Override
49    public double getAverageRating() {
50        if (ratings.isEmpty()) return 0;
51        return ratings.stream().mapToInt(i -> i).average().orElse(0);
52    }
53
54    @Override
55    public int getTotalRatings() {
56        return ratings.size();
57    }
58
59    // ===== Downloadable implementation =====
60    @Override
61    public void download(String path) {
62        System.out.println("Downloading "" + title + "" (" + getDownloadInfo()
63            + ") to " + path);
64    }
65
66    @Override
67    public double getFileSizeMB() {
68        return fileSizeMB;
69    }
70
71    @Override
72    public String toString() {
73        return """ + title + "" by " + artist;
74    }
75}
java
1// Podcast implements Playable and Downloadable but NOT Rateable
2public class Podcast implements Playable, Downloadable {
3    private String title;
4    private String host;
5    private int episodeNumber;
6    private int durationSeconds;
7    private double fileSizeMB;
8
9    public Podcast(String title, String host, int episode,
10                   int durationSeconds, double fileSizeMB) {
11        this.title = title;
12        this.host = host;
13        this.episodeNumber = episode;
14        this.durationSeconds = durationSeconds;
15        this.fileSizeMB = fileSizeMB;
16    }
17
18    @Override
19    public void play() {
20        System.out.println("Playing podcast: "" + title
21            + "" Ep." + episodeNumber + " hosted by " + host);
22    }
23
24    @Override
25    public void pause() {
26        System.out.println("Paused podcast: "" + title + """);
27    }
28
29    @Override
30    public void stop() {
31        System.out.println("Stopped podcast: "" + title + """);
32    }
33
34    @Override
35    public int getDurationInSeconds() { return durationSeconds; }
36
37    @Override
38    public void download(String path) {
39        System.out.println("Downloading podcast episode to " + path);
40    }
41
42    @Override
43    public double getFileSizeMB() { return fileSizeMB; }
44}
java
1public class MediaPlayerDemo {
2    public static void main(String[] args) {
3        Song song = new Song("Bohemian Rhapsody", "Queen", 355, 8.2);
4        Podcast podcast = new Podcast("Code Talk", "Jane Dev", 42, 3600, 52.5);
5
6        // Using the INTERFACE type -- maximum flexibility!
7        List<Playable> playlist = new ArrayList<>();
8        playlist.add(song);      // Song IS Playable
9        playlist.add(podcast);   // Podcast IS Playable
10
11        // Play everything in the playlist -- works with ANY Playable!
12        for (Playable item : playlist) {
13            item.play();
14            System.out.println("Duration: " + item.getDurationInSeconds() + "s");
15        }
16
17        // Only downloadable items
18        List<Downloadable> downloadQueue = new ArrayList<>();
19        downloadQueue.add(song);     // Song IS ALSO Downloadable
20        downloadQueue.add(podcast);  // Podcast IS ALSO Downloadable
21
22        for (Downloadable item : downloadQueue) {
23            System.out.println("Size: " + item.getDownloadInfo());
24            item.download("/downloads/");
25        }
26
27        // Only rateable items -- Podcast does NOT qualify!
28        Rateable rateableSong = song;  // Song IS Rateable
29        rateableSong.addRating(5);
30        rateableSong.addRating(4);
31        rateableSong.addRating(5);
32        System.out.println("Average rating: " + rateableSong.getAverageRating());
33        // Podcast is NOT Rateable, so this would be a compile error:
34        // Rateable rateablePodcast = podcast;  // NOPE!
35    }
36}

The Big Aha! Notice how the SAME Song object appears in both the \playlist\ (as a Playable) and the \downloadQueue\ (as a Downloadable). One object, viewed through different interface "lenses." This is the real power of interfaces -- they let you define capabilities independently, and a class can mix and match any combination of capabilities it needs.


Visual Mental Model

java
1    INTERFACES (contracts / capabilities)
2
3    +----------+   +----------+   +--------------+
4    | Playable |   | Rateable |   | Downloadable |
5    |----------|   |----------|   |--------------|
6    | play()   |   | addRating|   | download()   |
7    | pause()  |   | getAvg() |   | getFileSize()|
8    | stop()   |   | getTotal |   | getDownload  |
9    | getDur() |   +----------+   |    Info()    |
10    +----------+                  +--------------+
11         |    \            |       /        |
12         |     \           |      /         |
13    implements  implements implements  implements
14         |       \         |    /           |
15         v        v        v   v            v
16    +---------+     +----------+
17    | Podcast |     |   Song   |
18    |---------|     |----------|
19    | Playable|     | Playable |
20    | Download|     | Rateable |
21    +---------+     | Download |
22                    +----------+
23
24    Song = Playable + Rateable + Downloadable
25    Podcast = Playable + Downloadable (no Rateable!)
26
27    Abstract class:  "What you ARE" (is-a hierarchy)
28    Interface:       "What you CAN DO" (capabilities)

Real-World Analogy Recap

Interfaces are like professional certifications. A person (class) can earn multiple certifications (interfaces): CPR Certified, Scuba Licensed, Pilot Licensed. When a hospital needs someone who is CPR Certified, they do not care if you are a doctor, a nurse, or a lifeguard -- they just care that you have that certification (implement that interface). A lifeguard might be CPR Certified AND Scuba Licensed. A pilot might be Scuba Licensed AND Pilot Licensed. Each person picks the certifications relevant to them, and organizations filter by capability, not by job title.


Common Mistakes & Gotchas

  • Interface vs Abstract Class confusion: Use an interface when you want to define a CAPABILITY that many unrelated classes can share. Use an abstract class when you want to share STATE (fields) and partial implementation among closely related classes.
  • Implementing without overriding all methods: If you \implements\ an interface, you MUST provide bodies for ALL abstract methods. The only exception: if you declare your class \abstract\ itself.
  • Overusing default methods: Default methods were added for backward compatibility (so existing interfaces could add new methods without breaking all implementations). Do not use them as a way to make interfaces into abstract classes. Keep interfaces focused.
  • Too many methods in one interface: An interface with 15 methods is hard to implement. Prefer small, focused interfaces (Interface Segregation Principle). Better to have \Playable\, \Rateable\, and \Downloadable\ as separate interfaces than one giant \MediaCapable\ interface.
  • Fields in interfaces: All fields in interfaces are implicitly \public static final\ (constants). You cannot have instance variables in an interface. If you need state, use an abstract class.
  • Functional interface gotcha: An interface with exactly one abstract method is a functional interface and can be used with lambdas. Adding a second abstract method breaks all lambda usages -- be careful!

Interview Tip

When asked "When would you use an interface vs an abstract class?", structure your answer around three axes: (1) State: Abstract classes can have instance fields; interfaces can only have constants. (2) Inheritance: A class can implement many interfaces but extend only one class. (3) Relationship: Abstract classes model IS-A relationships among related types; interfaces model CAN-DO capabilities across unrelated types. Then give a concrete example: "A \List\ interface is perfect because ArrayList and LinkedList are very different internally but share the same contract."


Quick Quiz

  1. Can a class extend an abstract class AND implement multiple interfaces at the same time? Write the declaration syntax.
  2. What is a "functional interface" and why do lambdas require one? Give an example of one from the Java standard library.
  3. If two interfaces both have a default method with the same signature, and a class implements both, what happens? How do you resolve it?

Summary -- Key Takeaways

  • An interface is a pure contract -- it defines what a class CAN DO without dictating how or what the class IS.
  • A class can implement multiple interfaces, solving the limitation of single-class inheritance in Java.
  • Default methods (Java 8+) allow interfaces to provide optional implementations, but should be used sparingly.
  • Program to an interface, not an implementation -- this is one of the most important principles in software design. Use interface types for variables, parameters, and return types.