Skip to main content

Section 7.5 Implementing an Interface

Now that we have seen how interfaces define a contract with method signatures but no implementations, let’s explore how a class can use an interface by implementing it. When a class implements an interface, it must provide concrete implementations for all the methods declared in the interface. This ensures that any class following the interface adheres to the expected behavior. Let’s see how this works in practice.

Subsection 7.5.1 Using implements in a Class Declaration

When a class says implements SomeInterface, it promises to provide all the methods defined by that interface. Let’s update our MusicTrack and PodcastEpisode classes to implement Playable:
public class MusicTrack implements Playable {

    /**
     * The @Override annotation tells the compiler:
     * "I'm implementing a method from the interface."
     * If you misspell the method, you'll get a warning.
     */
    @Override
    public void play() {
        System.out.println("Playing music...");
    }
}

public class PodcastEpisode implements Playable {

    @Override
    public void play() {
        System.out.println("Playing podcast...");
    }
}
@Override isn’t strictly required, but it’s highly recommended. It explicitly signals your intent to Java, and if you mismatch the signature (like pLay() or play(String s)), the compiler immediately warns you.
With implements, the compiler ensures you match void play() exactly. If you omit play(), or if you rename it to something else, you’ll get a compile-time error. For example:
// WRONG EXAMPLE: Missing 'play()'
public class Audiobook implements Playable {
    // no method provided!
}
This error means "you promised to implement play(), but you didn’t!" The compiler halts, forcing you to fix the issue before running. Once we add the required method, it compiles fine:
// Correct fix:
public class Audiobook implements Playable {

    @Override
    public void play() {
        System.out.println("Playing audiobook...");
    }
}
What if I want partial implementation? Then you can declare your class abstract, meaning it’s not fully complete and can’t be instantiated. Important Note for Beginners: Abstract classes are a more advanced feature you’ll learn later. For now, if the compiler complains you haven’t implemented all methods, simply add the missing ones to your class. In later chapters will explore abstract classes in more depth, so don’t worry if this concept doesn’t fully make sense yet. Just focus on implementing all the interface methods in your regular classes for now.
Another mismatch example: Extra parameters or wrong return type
public interface Playable {
    void play();
}

public class BadImplementation implements Playable {

    // This tries to use an extra parameter:
    @Override
    public void play(String track) { // but interface expects play()
        System.out.println("Attempting to play " + track);
    }
}
The compiler clearly says "does not override abstract method play() in Playable," because play(String) is not the same signature as play(). Java’s strictness ensures consistent method contracts.

Subsection 7.5.2 Writing a Method That Expects an Interface

Now that MusicTrack and PodcastEpisode both implement Playable, let’s simplify playMedia dramatically. Instead of accepting Object media and guessing its type, we can require a Playable parameter:
public static void playMedia(Playable media) {
    // Because 'media' implements Playable, it must have 'play()'.
    media.play(); 
}

public static void main(String[] args) {
    MusicTrack music = new MusicTrack();
    PodcastEpisode podcast = new PodcastEpisode();

    // Both are valid 'Playable' objects, so we can pass them in directly:
    playMedia(music);   // prints "Playing music..."
    playMedia(podcast); // prints "Playing podcast..."
}
No casting, no instanceof—just media.play(). If we later add:
public class Audiobook implements Playable {
    @Override
    public void play() {
        System.out.println("Playing audiobook...");
    }
}

// ... in main:
Audiobook book = new Audiobook();
playMedia(book); // prints "Playing audiobook..."
We don’t need to modify the playMedia method at all. It automatically works with any new class that implements Playable. That’s the power of interfaces for easily extending your code—no need to rewrite or expand older methods. If you created a new class Livestream implementing Playable, you could call playMedia(new Livestream()) with zero changes elsewhere!
Real-World Analogy (Polymorphism): Think of a universal "Play" button that works on different devices: a DVD player, a streaming service, or a music player. Each device does something unique when you press "Play," but from your perspective, it’s a single button. That’s exactly what an interface method does in code: one method name (play()) triggers different implementations depending on the actual class or device.

Checkpoint 7.5.1. Interface Implementation.

What happens if a class incorrectly implements an interface method by adding extra parameters or using a different return type?
  • The program will still compile, but the interface method will not be considered overridden.
  • Java enforces strict adherence to interface method signatures. If the signature does not match, the compiler does not allow the implementation, and the program fails to compile.
  • The program will not compile because the method signature must exactly match the interface definition.
  • When implementing an interface, the method signature must match exactly (same method name, parameters, and return type). If extra parameters are added or the return type is changed, the method does not correctly override the interface method, causing a compilation error.
  • The program will compile, but the extra parameters will be ignored.
  • The Java compiler does not ignore extra parameters in method implementations. If an interface specifies a method signature, an implementation must match it exactly, otherwise, a compilation error occurs.
  • The program will compile only if the method has a compatible return type.
  • The return type must exactly match, except in cases of covariant return types (where the return type in the subclass is a subclass of the original return type). However, primitive return types like int and double are not covariant, so an incompatible return type will cause a compilation error.

Checkpoint 7.5.2.

Consider the following Java interface and class implementation:
interface Calculator {
    int add(int a, int b);
}

class MyCalculator implements Calculator {
   public double add(int a, int b) {
        return a + b;
    }
}
The code does not compile. How can this issue be fixed?
  • Modify Calculator so that add(int, int) returns double instead of int.
  • While this change would allow MyCalculator to compile, it alters the interface definition, which could affect other classes implementing Calculator. Interfaces should be designed carefully to avoid breaking existing implementations.
  • Change the return type of add(int, int) in MyCalculator to int.
  • To correctly implement an interface method, the return type must match exactly. Since Calculator defines add(int, int) with an int return type, MyCalculator must also return an int. Changing the method to return int ensures proper overriding and successful compilation.
  • Use method overriding with @Override and let the compiler infer the correct return type.
  • The @Override annotation does not change the return type rules. The compiler does not "infer" a return type; the method must explicitly match the interface’s method signature, including its return type.
  • Overload the add method in MyCalculator by adding another version with an int return type.
  • Overloading (having multiple methods with the same name but different parameters or return types) does not fix the issue. The class must override the method from the interface, not create an additional method.
You have attempted of activities on this page.