Review

In class we saw that each type of collection has an interface (e.g. List, Set) and various implementations that implement those interfaces (e.g. ArrayList/LinkedList for List and TreeSet/HashSet for Set). We use interfaces to make our code more general; for example we can write code that works with any Set rather than having to write it once to work for TreeSet and another time for HashSet.

In Java, interfaces are used to make the code more general by making a promise that any class that implements the interface is guaranteed to have those methods. In this reading, we will see how to write an interface and make your classes implement them.

Writing an interface

Writing an interface is very similar to writing a class, but you use the keyword interface instead of class.

For example, we are going to make an IntList interface that acts like Java’s List but to go along with our ArrayIntList. We’ll see next week another way to implement an IntList called a LinkedIntList.

public interface IntList {
    // TODO fill this in
}

Recall that an interface is a way of specifying “all classes that implement my interface are required to have these methods”. To require all classes that are IntLists to have an add method, we write the method header for the method we want without a body (since interfaces don’t provide implementations, only requirements). We would then write

public interface IntList {
    public void add(int value);  // notice ; instead of { } with method body
}

Now any class that claims to be an IntList must have a method that matches the signature add(int). There are many other methods we probably want to make sure anyone who is an IntList has, so we can add more method requirements as so:

public interface IntList {
    public void add(int value);
    public void add(int index, int value);
    public boolean contains(int value);
    public int get(int index);
    public void remove(int index);
    public int size();
}

Now that we have the IntList interface, we can write methods that work with it! Remember that if we have a variable of type IntList, we are allowed to call any of the methods required by the IntList interface on that variable since Java will enforce that any class that implements the interface will have all the required methods.

For example if we wanted to write a method that took an IntList and printed all the values in the list, we could write the following

public static void printList(IntList list) {
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
}

Now let’s try calling the printList method.

public static void main(String[] args) {
    ArrayIntList list = new ArrayIntList();
    list.add(1);
    list.add(2);
    list.add(3);

    printList(list);
}

Unfortunately we will end up getting a compiler error because Java doesn’t know that ArrayIntList is an IntList by default. We have to do something special in the ArrayIntList class to tell Java that it has all the IntList methods.

Making ArrayIntList an IntList

We have all the methods we need implemented in ArrayIntList (and some more!), we just need to tell Java that ArrayIntList is actually an IntList. To do that we just have to change the class header to

public class ArrayIntList implements IntList

This is telling Java that we promise to implement all the methods defined in IntList. If we were to forget a method (say contains(int)), then our class would not compile because it did not implement all the methods IntList asked for!

After adding these two tokens, we are now able to call printList passing in an ArrayIntList. In fact, now that we have an interface for it, it would be better style to define the variable in the client code as

IntList list = new ArrayIntList();