Section 7.3 Introducing Interfaces
Interfaces in Java allow us to define a common set of behaviors that multiple classes can follow. Unlike regular classes, an interface only specifies what a class should do, not how it should do it. This helps keep code organized and makes it easier to work with different types of objects in a consistent way. In this section, we’ll explore how interfaces work and why they are useful in Java programming
Subsection 7.3.1 Why Use Interfaces? A Media Player with Multiple Classes
Suppose you want to write a simple media player that can handle multiple types of content—like music tracks, podcasts, or audiobooks. Initially, you might write two separate classes:
// Two different classes with different method names
public class MusicTrack {
public void playMusic() {
System.out.println("Playing music…");
}
}
public class PodcastEpisode {
public void startPlaying() {
System.out.println("Playing podcast…");
}
}
Then you attempt to create a single method
playMedia that handles either kind of content. A naive approach might look like this:
public static void playMedia(Object media) {
if (media instanceof MusicTrack) {
((MusicTrack) media).playMusic();
} else if (media instanceof PodcastEpisode) {
((PodcastEpisode) media).startPlaying();
}
}
Here, two new concepts appear:
-
instanceof: Checks if an object belongs to a specific class. -
Casting: Explicitly tells Java the type of the object. It’s like labeling a generic "box" (
Object) with a specific sticker (this is actually aMusicTrack!).
Why use
Object at all? Because Object is Java’s most general type. Every class in Java automatically extends Object. This means that all Java objects share a common foundation and can be referenced as type Object when needed. We’ll explore more about what this means later when we introduce inheritance, but for now, just focus on the idea that Object is the most general type in Java.
This approach "works," but is awkward and error-prone:
-
You must cast separately for each type—imagine adding more classes like
Audiobook,Livestream, etc. -
Different method names (
playMusic()vs.startPlaying()) force multiple conditional checks.
Wouldn’t it be simpler if each class used the same method name, such as
play()? Then you could eliminate instanceof and casting entirely. That’s exactly what Java interfaces help us achieve—defining a "contract" (e.g., void play()) that every implementor must fulfill. Java’s compiler enforces this contract by refusing to compile code that breaks it.
Mini Example: Compiler Enforcement in Action
// A tiny interface as a contract
public interface MiniInterface {
void doSomething();
}
// A class that 'implements' MiniInterface
// but FAILS to provide doSomething():
public class BadImplementation implements MiniInterface {
// forgot doSomething()!
}
Encouragement About Errors: Don’t worry if you see errors like these! Compiler errors are your friend—they point you straight to what’s missing or incorrect. Encountering them is normal and expected. Every programmer repeatedly relies on compiler feedback to correct mistakes quickly, rather than hunting for them at runtime.
You have attempted of activities on this page.
