SHARE
Facebook X Pinterest WhatsApp

Interfaces with inheritance

Bruce Eckel’s Thinking in Java Contents | Prev | Next The interface keyword takes the abstract concept one step further. You could think of it as a “pure” abstract class. It allows the creator to establish the form for a class: method names, argument lists and return types, but no method bodies. An interface can […]

Written By
thumbnail
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

The


interface
keyword takes the abstract

concept
one step further. You could think of it as a “pure” abstract

class.
It allows the creator to establish the form for a class: method names, argument
lists and return types, but no method bodies. An
interface
can also contain data members of primitive types, but these are implicitly
static
and
final.
An
interface
provides only a form, but no
implementation.

An


interface

says: “This is what all classes that


implement

this particular interface will look like.” Thus, any code that uses a


particular


interface

knows what methods might be called for that


interface

,


and that’s all. So the


interface

is used to establish a “protocol” between classes. (Some


object-oriented programming languages have a keyword called

protocol
to do the same thing.)

To


create an


interface

,


use the


interface

keyword instead of the


class

keyword. Like a class, you can add the

public
keyword before the
interface
keyword
(but only if that
interface
is defined in a file of the same name) or leave it off to give “
friendly”
status.

To


make a class that conforms to a particular


interface

(or group of


interface

s)


use the

implements
keyword. You’re saying “The
interface
is what it looks like and here’s how it
works.”
Other than that, it bears a strong resemblance to inheritance. The diagram for
the instrument example shows this:

Once


you’ve implemented an


interface

,


that implementation becomes an ordinary class that can be extended in the


regular way.

You


can choose to explicitly declare the method declarations in an


interface

as


public

.


But they are


public

even if you don’t say it. So when you


implement

an


interface

,


the methods from the


interface

must be defined as


public.

Otherwise they would default to “friendly” and you’d be


restricting the accessibility of a method during inheritance, which is not


allowed by the Java compiler.

You


can see this in the modified version of the


Instrument

example. Note that every method in the


interface

is strictly a declaration, which is the only thing the compiler allows. In


addition, none of the methods in


Instrument5

are declared as


public

,


but they’re automatically


public

anyway:

//: Music5.java
// Interfaces
import java.util.*;
 
interface Instrument5 {
  // Compile-time constant:
  int i = 5; // static & final
  // Cannot have method definitions:
  void play(); // Automatically public
  String what();
  void adjust();
}
 
class Wind5 implements Instrument5 {
  public void play() {
    System.out.println("Wind5.play()");
  }
  public String what() { return "Wind5"; }
  public void adjust() {}
}
 
class Percussion5 implements Instrument5 {
  public void play() {
    System.out.println("Percussion5.play()");
  }
  public String what() { return "Percussion5"; }
  public void adjust() {}
}
 
class Stringed5 implements Instrument5 {
  public void play() {
    System.out.println("Stringed5.play()");
  }
  public String what() { return "Stringed5"; }
  public void adjust() {}
}
 
class Brass5 extends Wind5 {
  public void play() {
    System.out.println("Brass5.play()");
  }
  public void adjust() {
    System.out.println("Brass5.adjust()");
  }
}
 
class Woodwind5 extends Wind5 {
  public void play() {
    System.out.println("Woodwind5.play()");
  }
  public String what() { return "Woodwind5"; }
}
 
public class Music5 {
  // Doesn't care about type, so new types
  // added to the system still work right:
  static void tune(Instrument5 i) {
    // ...
    i.play();
  }
  static void tuneAll(Instrument5[] e) {
    for(int i = 0; i < e.length; i++)
      tune(e[i]);
  }
  public static void main(String[] args) {
    Instrument5[] orchestra = new Instrument5[5];
    int i = 0;
    // Upcasting during addition to the array:
    orchestra[i++] = new Wind5();
    orchestra[i++] = new Percussion5();
    orchestra[i++] = new Stringed5();
    orchestra[i++] = new Brass5();
    orchestra[i++] = new Woodwind5();
    tuneAll(orchestra);
  }
} ///:~ 

The


rest of the code works the same. It doesn’t matter if you are

upcasting
to a “regular” class called
Instrument5,
an
abstract
class called
Instrument5,
or to an
interface
called
Instrument5.
The behavior is the same. In fact, you can see in the
tune( )
method that there isn’t any evidence about whether
Instrument5
is a “regular” class, an
abstract
class or an
interface.
This is the intent: Each approach gives the programmer different control over
the way objects are created and used.

“Multiple
inheritance” in Java

The


interface

isn’t simply a “more pure” form of


abstract

class. It has a higher purpose than that. Because an


interface

has no implementation at all – that is, there is no storage associated


with an


interface


there’s


nothing to prevent many


interface

s


from being combined. This is valuable because there are times when you need to


say “An


x

is an


a
and

a


b
and

a


c

.”


In C++, this act of combining multiple class interfaces is called

multiple
inheritance
,
and it carries some rather sticky baggage because each class can have an
implementation. In Java, you can perform the same act, but only one of the
classes can have an implementation, so the problems seen in C++ do not occur
with Java when combining multiple interfaces:

In


a derived class, you aren’t forced to have a base class that is either an


abstract

or “concrete” (one with no


abstract

methods). If you


do

inherit from a non-


interface

,


you


can inherit from only one. All the rest of the base elements must be


interface

s.


You place all the interface names after the


implements

keyword


and separate them with commas. You can have as many


interface

s


as you want and each one becomes an independent type that you can upcast to.


The following example shows a concrete class combined with several


interface

s


to produce a new class:

//: Adventure.java
// Multiple interfaces
import java.util.*;
 
interface CanFight {
  void fight();
}
 
interface CanSwim {
  void swim();
}
 
interface CanFly {
  void fly();
}
 
class ActionCharacter {
  public void fight() {}
}
 
class Hero extends ActionCharacter
    implements CanFight, CanSwim, CanFly {
  public void swim() {}
  public void fly() {}
}
 
public class Adventure {
  static void t(CanFight x) { x.fight(); }
  static void u(CanSwim x) { x.swim(); }
  static void v(CanFly x) { x.fly(); }
  static void w(ActionCharacter x) { x.fight(); }
  public static void main(String[] args) {
    Hero i = new Hero();
    t(i); // Treat it as a CanFight
    u(i); // Treat it as a CanSwim
    v(i); // Treat it as a CanFly
    w(i); // Treat it as an ActionCharacter
  }
} ///:~ 

You


can see that


Hero

combines the concrete class


ActionCharacter

with the interfaces


CanFight

,


CanSwim

,


and


CanFly

.


When you combine a concrete class with interfaces this way, the concrete class


must come first, then the interfaces. (The compiler gives an error otherwise.)

Note


that the signature for


fight( )

is the same in the


interface
CanFight

and the class


ActionCharacter

,


and that


fight( )

is


not

provided with a definition in


Hero

.


The rule for an


interface

is that you can inherit from it (as you will see shortly), but then


you’ve got another


interface

.


If you want to create an object of the new type, it must be a class with all


definitions provided. Even though


Hero

does not explicitly provide a definition for


fight( )

,


the definition comes along with


ActionCharacter

so it is automatically provided and it’s possible to create objects of


Hero

.

In


class


Adventure

,


you can see that there are four methods that take as arguments the various


interfaces and the concrete class. When a


Hero

object is created, it can be passed to any of these methods, which means it is


being upcast to each


interface

in turn. Because of the way interfaces are designed in Java, this works without


a hitch and without any particular effort on the part of the programmer.

Keep


in mind that the core reason for interfaces is shown in the above example: to


be able to upcast to more than one base type. However, a second reason for


using interfaces is the same as using an


abstract

base


class: to prevent the client programmer from making an object of this class and


to establish that it is only an interface. This brings up a question: Should


you use an

interface
or an
abstract
class? An
interface
gives you the benefits of an
abstract
class
and
the benefits of an
interface,
so if it’s possible to create your base class without any method
definitions or member variables you should always prefer
interfaces
to
abstract
classes. In fact, if you know something is going to be a base class, your first
choice should be to make it an
interface,
and only if you’re forced to have method definitions or member variables
should you change to an
abstract
class.

Extending
an interface

with
inheritance

You


can easily add new method declarations to an

interface
using inheritance, and you can also combine several
interfaces
into a new
interface
with inheritance. In both cases you get a new
interface,
as seen in this example:
//: HorrorShow.java
// Extending an interface with inheritance
 
interface Monster {
  void menace();
}
 
interface DangerousMonster extends Monster {
  void destroy();
}
 
interface Lethal {
  void kill();
}
 
class DragonZilla implements DangerousMonster {
  public void menace() {}
  public void destroy() {}
}
 
interface Vampire
    extends DangerousMonster, Lethal {
  void drinkBlood();
}
 
class HorrorShow {
  static void u(Monster b) { b.menace(); }
  static void v(DangerousMonster d) {
    d.menace();
    d.destroy();
  }
  public static void main(String[] args) {
    DragonZilla if2 = new DragonZilla();
    u(if2);
    v(if2);
  }
} ///:~ 
DangerousMonster

is a simple extension to


Monster

that produces a new


interface

.


This is implemented in


DragonZilla

.

The


syntax used in


Vampire

works


only

when inheriting interfaces. Normally, you can use

extends
with only a single class, but since an
interface
can be made from multiple other interfaces,
extends
can refer to multiple base interfaces when building a new
interface.
As you can see, the
interface
names are simply separated with commas.

Grouping
constants

Because


any fields you put into an


interface

are automatically


static

and


final

,


the


interface

is a convenient tool for

creating
groups of constant values, much as you would with an
enum
in C or C++. For example:
//: Months.java
// Using interfaces to create groups of constants
package c07;
 
public interface Months {
  int
    JANUARY = 1, FEBRUARY = 2, MARCH = 3,
    APRIL = 4, MAY = 5, JUNE = 6, JULY = 7,
    AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10,
    NOVEMBER = 11, DECEMBER = 12;
} ///:~ 

Notice


the Java style of using all uppercase letters (with underscores to separate


multiple words in a single identifier) for


static
final

primitives that have constant initializers – that is, for compile-time


constants.

The


fields in an


interface

are


automatically


public

,


so it’s unnecessary to specify that.

Now


you can use the constants from outside the package by importing


c07.*

or


c07.Months

just as you would with any other package, and referencing the values with


expressions like


Months.JANUARY

.


Of course, what you get is just an


int

so there isn’t the extra type safety that C++’s


enum

has, but this (commonly-used) technique is certainly an improvement over


hard-coding numbers into your programs. (This is often referred to as using


“magic numbers” and it produces very difficult-to-maintain code.)

If


you do want extra type safety, you can build a class like this:


[28]
//: Month2.java
// A more robust enumeration system
package c07;
 
public final class Month2 {
  private String name;
  private Month2(String nm) { name = nm; }
  public String toString() { return name; }
  public final static Month2
    JAN = new Month2("January"),
    FEB = new Month2("February"),
    MAR = new Month2("March"),
    APR = new Month2("April"),
    MAY = new Month2("May"),
    JUN = new Month2("June"),
    JUL = new Month2("July"),
    AUG = new Month2("August"),
    SEP = new Month2("September"),
    OCT = new Month2("October"),
    NOV = new Month2("November"),
    DEC = new Month2("December");
  public final static Month2[] month =  {
    JAN, JAN, FEB, MAR, APR, MAY, JUN,
    JUL, AUG, SEP, OCT, NOV, DEC
  };
  public static void main(String[] args) {
    Month2 m = Month2.JAN;
    System.out.println(m);
    m = Month2.month[12];
    System.out.println(m);
    System.out.println(m == Month2.DEC);
    System.out.println(m.equals(Month2.DEC));
  }
} ///:~ 

The


class is called


Month2

since there’s already a


Month

in the standard Java library. It’s a


final

class with a


private

constructor so no one can inherit from it or make any instances of it. The only


instances are the


final
static

ones created in the class itself:


JAN

,


FEB

,


MAR

,


etc. These objects are also used in the array


month

,


which lets you choose months by number instead of by name. (Notice the extra


JAN

in the array to provide an offset by one, so that December is month 12.) In


main( )

you can see the

type
safety:
m
is a
Month2
object so it can be assigned only to a
Month2.
The previous example
Months.java
provided
only
int
values, so an
int
variable intended to represent a month could actually be given any integer
value, which wasn’t too safe.

This


approach also allows you to use


==

or


equals( )

interchangeably, as shown at the end of


main( )

.

Initializing
fields in interfaces

Fields


defined in interfaces are automatically


static

and


final

.


These cannot be “blank finals,” but they can be initialized with


non-constant expressions. For example:

//: RandVals.java
// Initializing interface fields with 
// non-constant initializers
import java.util.*;
 
public interface RandVals {
  int rint = (int)(Math.random() * 10);
  long rlong = (long)(Math.random() * 10);
  float rfloat = (float)(Math.random() * 10);
  double rdouble = Math.random() * 10;
} ///:~ 

Since


the fields are


static

,


they are initialized when the class is first loaded, upon first access of any


of the fields. Here’s a simple test:

//: TestRandVals.java
 
public class TestRandVals {
  public static void main(String[] args) {
    System.out.println(RandVals.rint);
    System.out.println(RandVals.rlong);
    System.out.println(RandVals.rfloat);
    System.out.println(RandVals.rdouble);
  }
} ///:~ 

The


fields, of course, are not part of the interface but instead are stored in the


static

storage area for that interface.



[28]

This approach was inspired by an e-mail from Rich Hoffarth.

Contents

|

Prev

|

Next

Recommended for you...

Top Five Most Popular Front-end Frameworks
Tapas Pal
Mar 5, 2018
DocFlex/Javadoc: Multi-Format Doclet & Rapid Doclet Development Tool
CodeGuru Staff
Apr 23, 2012
Top Down with Memorization Complexity
CodeGuru Staff
Feb 24, 2012
Building and Using the Secret Service Java API
CodeGuru Staff
Feb 21, 2012
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.