Lists of an interface, and interfaces as return types
A phone's media player plays voice memos and radio shows. From every item in its queue, it needs a title, a length in seconds, and a way to play it:
public interface Playable {
String title();
int seconds();
void play();
}
A list of Playables
A list's element type can be an interface too. Then the list holds objects of any class that implements it:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Playable> queue = new ArrayList<>();
queue.add(new VoiceMemo("Groceries", 45));
queue.add(new RadioShow("Morning News", 5));
queue.add(new VoiceMemo("Door code", 12));
int total = 0;
for (Playable item : queue) {
item.play();
total += item.seconds();
}
System.out.println("In the queue: " + total + " seconds");
Playable longest = longest(queue);
System.out.println("Longest: " + longest.title());
}
public static Playable longest(ArrayList<Playable> queue) {
Playable longest = queue.get(0);
for (Playable item : queue) {
if (item.seconds() > longest.seconds()) {
longest = item;
}
}
return longest;
}
}public interface Playable {
String title();
int seconds();
void play();
}public class VoiceMemo implements Playable {
private String title;
private int seconds;
public VoiceMemo(String title, int seconds) {
this.title = title;
this.seconds = seconds;
}
@Override
public String title() {
return this.title;
}
@Override
public int seconds() {
return this.seconds;
}
@Override
public void play() {
System.out.println("Memo: " + this.title);
}
}public class RadioShow implements Playable {
private String name;
private int minutes;
public RadioShow(String name, int minutes) {
this.name = name;
this.minutes = minutes;
}
@Override
public String title() {
return this.name;
}
@Override
public int seconds() {
return 60 * this.minutes;
}
@Override
public void play() {
System.out.println("On air: " + this.name);
}
}Memo: Groceries
On air: Morning News
Memo: Door code
In the queue: 357 seconds
Longest: Morning NewsArrayList<Playable>holds memos and shows side by side.addaccepts a VoiceMemo because a VoiceMemo is a Playable.- The loop variable
itemhas the type Playable. Each time round, it refers to one object, and that object'splayruns: a memo's printsMemo:, a show's printsOn air:. The loop doesn't know or care which kind each item is. - A new kind of item, such as a chapter of an audiobook, would be one more class that implements Playable. The loop wouldn't change.
- The class names VoiceMemo and RadioShow appear only where the objects are made. Everything after that works with Playable.
Returning a Playable
longest has the return type Playable. It returns whichever object in the queue has the most seconds, and the caller keeps it in a Playable variable, so the caller may use Playable's methods on it.
- The object that comes back is still what it was: the radio show.
longest(queue).play()would printOn air: Morning News. - A method can also create an object and return it as a Playable. The caller then doesn't even need to know which class it got. The last challenge of this step does that.