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.
Interfaces¶
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 IntList
s 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();
Stacks and Queues¶
In class today, we will introduce two new abstract data types: Stacks and Queues. Stacks and Queues are, on their own, very simplified data structures that don’t provide many operations. The both support operations to add and remove data from them, but the semantics for the ordering data is removed differs.
We will discuss why these ADTs are useful and how to use their Java counterparts in class, but we just wanted to give a brief overview of the object of study for today’s class.
Stacks¶
Stacks represent data where each new element gets “stacked on top” of the last.
An useful analogy is to think about a stack of lunch trays. Every time you get a lunch tray, you grab the one from the top. When cafeteria brings a clean lunch tray out to the stack, they put them on top. In other words, you always add new values at the top of the stack and when you remove values, you remove the one most recently added.
We sometimes call Stacks a Last In First Out structure or LIFO for short.
The operations the Stack ADT has are:
- push: To add a new value at the top of the stack
- pop: To remove the value from the top of the stack
- peek: To look at, but not remove, the value at the top of the stack.
Pictorially, this data structure is represented in the following image:
We’ll discuss more analogies and uses for Stacks in class.
Queues¶
Queues represent data where each new elements get added at the end and when removing values, we remove from the front.
An useful analogy is to think about a line of people at the store; in fact, some English speaking countries, they refer to this line as a “queue”! Every time a new person comes in line, they join at the back. When the checker is ready to help the next person, they get the person from the front.
We sometimes call Queues a First In, First Out structure or FIFO for short.
The operations the Queue ADT has are:
- add: To add a new value at the end of the queue
- remove: To remove the value from the front of the queue
- peek: To look at, but not remove, the value at the front of the queue
Pictorially, this data structure is represented in the following image:
We’ll discuss more analogies and uses for Queues in class.
Recap¶
- Interfaces let us define required methods that all classes that implement that interface must have. Importantly, interfaces don’t specify any code for how to do the methods, just a requirement of method headers.
- A class must explicitly say it
implements
an interface to be usable in any place the interface type is requested. - When using the interface type for your variable, you are restricting yourself to only using methods required by that interface. For example, you couldn’t use extra methods defined in
ArrayIntList
that aren’t in theIntList
interface if your variable is typeIntList
. - Stack is a simple ADT that allow clients to add and remove values only from the top of the stack.
- Queue is a simple ADT that allows clients to add values at the end of the queue, and remove values from the front.