An interface is a description of a set of
methods that conforming implementing classes must have.
Like A Class With Restrictions
Under the hood, an interface is like a class with
some restrictions.
- All its methods must be abstract
instance methods, no static methods allowed.
However you don’t declare the methods abstract.
That is implicit.
- Yet, all the variables defined in an interface must
be static final,
i.e. constants. Happily the values need not be known at compile time. You
can do some computation at class load time to compute the values. The variables
need not be just simple ints and Strings.
They can be any type. Normally you leave off the static
final as it is implit.
- No static initialiser blocks. You must do your
initialisations in one line per variable. And, of course, no static
initialiser helper methods defined in the interface.
If you need them, them must be defined outside the interface.
extend or implement?
- a class extends another class.
- a class implements one or more interfaces.
- an interface extends one of more interfaces.
Instantiating
interface methods are always instance methods. To
use them, there must be some associated Object that implements the interface.
You can’t instantiate an interface directly,
but you can instantiate a class that implements an interface.
References to an Object can by via the class
name, via one of its superclass names, or one of its interface
names.
Sample Code
Multiple Inheritance
In return for these restrictions, interfaces possess a feature that classes do
not — they can be multiply inherited. A new class can extend
only one superclass to inherit methods and variables from, however, a class can implement
multiple interfaces.
An interface can extend
several other interfaces. An interface enforces how
some of your methods must look to the outside world. It says nothing about how
you implement them. In contrast, a class usually
brings with it some default implementations.
Implied Modifiers
All methods in an interface are implicitly declared
public and abstract.
All variables in an interface must be constants.
They are implicitly declared public
static final.
The Business Metaphor
You won’t see many interfaces in small programs. However, they are
invaluable in large projects with many classes for managing the complicated
interactions between the classes. Managing a large set of classes is a bit like
managing a giant bureaucracy. You need formal job descriptions and formal
descriptions of who reports what information to whom, and who can ask what
services of whom. If you try to manage large collections of interacting classes
without using interfaces, every class becomes inextricably intertwined with all
the other classes and you can’t change anything without breaking
everything. You also get into chicken and egg problems. How can I test (or even
compile) my code without all the other classes I interact with fully functional?
You can’t keep track of the flow of information. You have no idea how the
whole thing works, even if it does.
I will develop this metaphor that will only gradually come clear over the years
as you experiment with interfaces. An interface is
like a role description. A person in a bureaucracy may play several roles:
filing clerk, keeper of petty cash, manager of the coffee machine. You are
restricted to a subset of her total capabilities when you interact with her in
each of her roles.
For someone to temporarily take over as manager of the coffee machine, all they
need assume is the one role, not all the capabilities of the usual multi-talented
coffee lady. The role description describes the minimal capabilities for
someone to pinch hit as a coffee machine manager. Even a male can be the coffee
lady.
With clearly defined roles, it is easy to ask, do you have the capabilities to
pinch hit as coffee lady? You don’t have to check out the necessary skills
one by one. An interface is like a skill set
summary.
In a hierarchical business organisation, each person has a formal set of
responsibilities, information to be passed to superiors, information to be
gleaned from underlings, commands taken from superiors, and commands given to
underlings… Most people in an organisation play many roles, depending on
whom they are talking to. Underlings are severely restricted in the services
they can demand of the president. Interfaces formally define the precise set of
services each class must provide in a given role. Roles simplify interactions.
The requestor knows what services are guaranteed to be provided, and interfaces
prevent the requestor from asking for services outside the formally agreed on
role, even if the requestee is capable of providing them.
With interfaces, it makes who fulfills a role interchangeable. Nobody
informally comes to rely on the additional petty cash skills of the original
coffee lady, unless they formally interacted with the coffee lady also in
the role of petty cash manager. Different people could pinch hit for a
vacationing coffee lady, one taking over her coffee lady role and one taking
over her petty cash manager role. Interfaces allow a class to say to other
classes, if you want to interact with me in role A, you must be capable of
assuming roles B, C and D. It makes it much simpler to plug classes together if
all you have to do is find a matching set of compatible roles (interfaces). If
they won’t fit, it is clear what minimal work you would have to do
to upgrade the skill set (methods), to allow a class to act in a new role, and
hence to allow it to interact with some other particular class.
Role descriptions, like interfaces, can be nested (multiply inherited). The role
description for a telephone supervisor naturally assumes capability of also
acting as an operator, and also the role of petty cash manager.
Marker Interfaces
There are some dummy marker interfaces without any methods that don’t
require you to write any code to implement them. They include Serializable
(note the American z spelling) and Cloneable. All you
do is add the line implements Serializable to the
class definition line, and presto, your class can partake in pickling.
Duct Tape
Interfaces are the duct tape of Java. Imagine that JApplet
had been developed totally independently of Applet. (It wasn’t. Applet
is a subclass of Applet.) How could you write some
code that worked with both Applet and JApplet
objects, letting you get at the methods the two have in common? In other words,
how can you treat Objects identically when they belong to similar classes, with
many identically named methods, but where that set of common methods is not
reflected in a common base class?
You could use Java’s duct tape — the interface.
You would define an interface say GeneralApplet
with some of the methods common to Applet and JApplet.
You would then modify both Applet and JApplet
to implement your GeneralApplet interface.
This is very easy to do, just add the words implements
GeneralApplet to the class definition line of both Applet
and JApplet. You now have a GeneralApplet
reference that could be either an Applet or JApplet
decided at runtime. e.g.
You would have glued together classes that came from quite different ancestries.
If necessary, you can mask slight differences in the method signatures of the
two classes with some interface wrapper methods.
Hymn Of Praise
By using roles you describe the bare bones of the interactions. You make clear
what skills a class has are and are not necessary to fulfill a given role. This
pruning out all unessential skills from consideration make the interactions much
easier to understand. Avoiding interfaces is a great way to write unmaintainable
code.
You will find yourself using interfaces more and more as you work on complex
projects. They let you simplify the possible interactions between groups of
classes to just what is needed. Interfaces formalise, document and enforce the
interactions between classes. They make code components more independent and
reusable. Pieces of code can be written even when the code it needs to interact
with is not written yet or is currently not compilable. In GUIs, where you have
panels within panels communicating, you will find it helps immensely to define
an interface for each parent listener callback
delegate, even when there is only one caller class.
Interfaces give a much finer degree of control of how classes interact than the public/
private scheme.
Gotchas
Eclipse refactoring leaves array constants behind when you ask it to move them
off to an interface. However, you can move them
manually yourself. It is perfectly ok to have array constants in an interface.
Interface Or Abstract Class
The Interface Antipattern
It is considered bad form to write an interface
with nothing but static final
constants it in. An interface should have at least
one abstract method. If all you want is a
collection of constants, use an ordinary class with import
static
Easy Maintenance
Interfaces have yet another use — in writing easy-to-maintain code. Let us
assume you created an ArrayList, then later had to
change your code so that you used a Vector instead,
and then later realised a LinkedList would be the best
way to handle it. You would have to change every ArrayList
cast and reference to Vector then later to LinkedList.
You might accidentally change some unrelated ArrayList.
If instead you used the interface List
as your reference type, which these three classes share in common, the only
thing that would have to change is the new ArrayList(300);
All the rest could stay as List. Let me put it yet
another way. If you wrote a method that expected a List
parameter, it would happily work with either an ArrayList,
Vector or LinkedList. You
can write more generic code using interfaces.
Reusable Code, Plug-Compatible
Yet another advantage of using interfaces is it makes the type system less
prissy when it does not really matter. Anything that can implement List
is roughly interchangeable. You can work with a mixture of Vectors,
ArrayLists, LinkedLists, and OSVectorLists
(ObjectStore persistent arrays), etc. and for the most part, all just comes out
in the wash in the interactions. It is as though everything were a one-size-fits-all
List.
When you use an interface, you lower the bar to
potential class interactions, and hence reusability. You demand fit only where
fit really matters.
Compilation Efficiency
Yet another advantage of using interfaces comes when you have a large project.
If you modify a method, that class has to be recompiled, but just in case you
changed one of the method signatures, all the code that calls that method has to
be recompiled too. If you use an interface, and don’t
change the interface (which lives in a separate
file from the implementations), changing just the interface
implementation classes, nothing need be recompiled, so long as those classes
accessed via the interface name rather than
specific class name, e.g. by using factories and interface
reference names. This is another example of the adage "All computer
programs can be solved by adding sufficient layers of indirection." In fact
you can write and compile code to call methods in an interface
specification even before anyone has written any implemenatations.
What You Don’t Specify
You can’t specify static methods in an interface.
All interface methods are instance methods. Even if
you could, how would you invoke the static method?
There would be no way to invoke it via its interface
name, (How would the compiler know which implementation version you wanted?) so
there would be not much point in it. I think a static declaration still might be
useful as to the implementor of an interface to
remind him to supply a useful static method to be
invoked explicitly via its class name.
You don’t need to specify public in the interface
method definitions. That is presumed. However, when you go to implement the interface,
you need to specifically spell out the public, so I
find it easier to specify public in the interface
to make them more useful templates. IDEs today are getting smarter and will
insert it for you when you use wizards to generate a skeleton implementation of
an interface.
I don’t recommend this, but you can also leave off the static
finals on your interface constants.
You don’t specify synchronized in your interface
method declarations. This is an implementation detail.
Learning More