Interfaces

Interfaces, similar to abstract classes, contain a collection of abstract methods. With abstract classes, you are able to create incomplete classes and rely on subclasses to implement the rest. Essentially, abstract classes are just normal classes with at least one abstract method. Interfaces are similar to abstract classes, but the difference is that interfaces have only unimplemented methods and nothing else, whereas abstract classes have a mix of implemented and abstract methods. Interfaces help guarantee that all subclasses have at the bare minimum the methods specified in the interface. Declaring variables as an interface type also helps your code stay flexible by allowing you to easily change the subclasses the variables are instantiated with.

Interfaces are very useful for very abstract ideas, and although you might not have seen them yet, they are very commonly used in programming. For example, let’s say you want to create an Animal class. However, just having an Animal object probably wouldn’t be sufficient. What kind of animal is it? Does it live on land or sea? Does it walk or fly? Because you can’t answer any of these questions with an Animal class alone, you should make Animal an interface with a few methods that all animals should be able to perform, but without the method implementations (as these depend on the type of animal). With interfaces, creating unimplemented methods is similar to how you would do it in an abstract method, except you simply leave out the access level modifiers and don’t include abstract:

    public interface Animal {

        void makeNoise();

        void eat();

        ...

    }

Like with abstract classes, the following call will not compile because you cannot directly instantiate an Animal object:

    Animal a = new Animal();

Now you can have more specific classes, like Dog and Fish, extend this interface and each provide its own implementation details for the methods listed in the interface. However, with interfaces, you don’t extend them, you implement them:

    public class Dog implements Animal {

        /* field variables */

        public Dog() {

            /* implementation details */

        }

        public void makeNoise() {

            System.out.println("Bark");

        }

        public void eat() {

            System.out.println("Dog eats bone");

        }

        /* optional other methods */

    }

Since interfaces are such abstract ideas, they often include a very large hierarchy of classes, abstract classes, and even other interfaces extending and implementing each other, getting more and more concrete as you go further down the hierarchy. For example, you could easily change the Dog and Fish classes to be abstract, and then have other classes like Husky, Poodle and Goldfish extend from them. And, taking it even further, you could introduce two new interfaces, LandAnimal and SeaAnimal, that lie in between the Animal interface and the Dog and Fish abstract classes. As you can see, there are endless possibilities when it comes to interfaces.

The added benefit of having this kind of hierarchy is that you can choose the amount of flexibility you have. For example, take a look at the following two variables:

    Animal a = new Poodle();

    Dog d = new Poodle(); 

Both variables now hold a Poodle object. However, the first variable a is classified as an animal whereas the second d is classified as a dog. Both are valid code examples, although each offers its own benefits. One benefit of the first one is that variable a is more generally classified and therefore gives you a greater variety of animals to choose from, like a husky and even a goldfish, whereas since d is defined more specifically as a Dog, you can only change it to be a husky or another type of Dog. However, since a can be any type of animal, this also means there are more restrictions to what methods are available to it.

Variable d can call all the methods listed in the Animal interface as well as any new methods provided in the Dog class (such as performTrick or chaseMailman) because it’s guaranteed to hold a dog. However, only methods included in the Animal interface (as well as the default methods included in the Object class, like toString) can be used by the variable a because it can be any type of animal, and animals like goldfish would not be able to perform a method in the Dog class, such as chasing a mailman.

To get even more methods, such as the methods defined specifically in the Poodle class, you could create a variable like this: Poodle p = new Poodle(). However, in some cases, it is better practice to define p as a Dog rather than a Poodle to give yourself a bit more flexibility in the future. If you needed to use a method defined in the Poodle class that isn’t defined in the Dog class, you could cast your Dog p into a Poodle each time you want to use one of those methods (if you don’t remember casting, it will be revisited in the next lesson about polymorphism). Of course, if you find yourself requiring a lot of the methods in the Poodle class, it is most likely better to define your variable as Poodle p = new Poodle().

In an upcoming lesson, you will be taking your first look at the Collection interface hierarchy, which defines several classes and interfaces that act as data structures. More specifically, you will be working with Lists and ArrayLists:

Collections Interface

Source: Neemeekaa Consulting

Notice how in this hierarchy some classes can implement multiple interfaces (e.g. public class LinkedList implements List, Queue, Deque). Also important to pay attention to are the different types of arrows. The filled arrows represent the extends keyword whereas the empty arrows represent the implements keyword. For example, you can see that ArrayList implements List, an interface, and LinkedHashSet extends HashSet, a class. If you pay close attention, you’ll also notice that the interfaces here extend the other interfaces rather than implementing them. This is a small detail but important to know if you ever go on to write your own hierarchy of classes and interfaces.

Lesson Quiz

1. Assume that A is an interface, B is an abstract class, and C is a class. Which of the following headers would result in an error?

    I. public class C extends B

    II. public class B implements A

    III. public class C extends A
a. I only
b. III only
c. I and II
d. II and III

2. Order classes, abstract classes, and interfaces in order from most concrete to most abstract.

a. Interfaces, classes, abstract classes
b. Classes, interfaces, abstract classes
c. Abstract classes, interfaces, classes
d. Classes, abstract classes, interfaces

Written by Alan Bi

Notice any mistakes? Please email us at [email protected] so that we can fix any inaccuracies.