Return to index

Object-Oriented
Programming Basics 3

 

Topics covered include :

  • Interfaces
  • Defining an Interface
  • Implementing an interface
  • Implementing multiple interfaces
  • Using an interface as a data type
  • Extending an interface

 

Interfaces

Java has 'single inheritance' only. This means that a child class inherits from only one parent class. Mostly this is all you need. But sometimes multiple inheritance would be convenient. Interfaces give Java some of the advantages of multiple inheritance without the disadvantages.

The chapter includes some small examples, but you will have to wait until you start programming graphical user interfaces to see interfaces used realistically. Interfaces are crucial to GUI programming.

Object oriented programming makes software behave like "real world" objects. This makes programs easier to think about and more reliable. In the real world, you often think about an object in several different ways. You can think of your car as a vehicle or as an item of taxable property. It would be convenient if software objects, also, could be thought of in several ways. But a Java object belongs to just one class.

In Java, an interface is used to express an aspect of a class other than what it inherits from its parent.

An interface is a collection of constants (not fields) and method declarations. The method declarations do not include an implementation (there is no method body.)

A child class that extends a parent class can also implement an interface to gain some additional behavior. Here is what an interface definition looks like:

interface InterfaceName {
      constant definitions
      method declarations (without implementations)
} 

A method declaration is simply an access modifier, return type, and method signature followed by a semicolon.

This looks somewhat like a class definition. But no objects can be instantiated from it. However, instances can be constructed from a class that implements an interface. A class definition implements an interface like this:

class SomeClass extends SomeParent implements interfaceName {
} 

A class always extends just one parent but may implement more than one interface.

Here is an example interface definition:

interface MyInterface {
      public final int aConstant = 32;       // a constant
      public final double pi = 3.14159;      // a constant

 

      public void methodA(int x);       // a method declaration
      double methodB();       // a method declaration
} 

The constants don't have to be separate from the methods, but doing so makes the interface easier to read. The key word 'final' indicates that the fields are constants - their values are 'final' - they cannot be modified.

A method in an interface cannot be made private. A method in an interface is public by default. Hence, in the example, methodB is public even though it does not say so.

  • A class that implements an interface must implement every method in the interface.
  • Every method must be public (this happens by default).
  • Constants from the interface can be used as if they had been defined in the implementing class.
  • Constants should not be redefined in an implementing class.

Variables cannot be put in an interface. Only constants and methods.

 

Implementing an Interface

A class definition must always extend one parent, but it can implement zero or more interfaces:

class SomeClass extends Parent implements SomeInterface, SomeOtherInterface {
       ordinary class definition body
} 
Here is a class definition that implements three interfaces :
public class BigClass extends Parent implements InterfaceA, InterfaceB, InterfaceC {
       ordinary class definition body
} 

The body of the class definition is the same as always. However, because it implements an interface, the body must have a definition (implementation) of each of the methods from the interface. The class definition can use access modifiers as usual.

Now BigClass must provide a method definition (implementation) for every method in each of the interfaces it declares that it implements. Note that any number of classes can implement the same interfaces.

Here is another class definition:

public class SmallClass implements InterfaceA {
       ordinary class definition body
} 

You might think that class SmallClass does not extend a base class, but it does. If no other class is extended, Object is the base class. Thus SmallClass extends class Object and implements InterfaceA.

Constants should be unique to each interface. However, it is ok if two interfaces require the same method. A class that implements both interfaces only needs to provide one complete method definition to satisfy both interfaces.

 

An Example Design Involving Interfaces

As an example, we will create a database program for a store. The store sells:

  • Goods, each of which has the attributes:
    • description
    • price
  • The goods can be categorised as one of the following:
    • Food - with an attribute "calories"
    • Toy - with an attribute "minimumAge", or
    • Book - with an attribute "author."

Of these goods, toys and books are taxable, but food is not. There are many other things that are taxable, such as services or entertainment so we need to have the concept "taxable" as a separate concept, not part of the concept of Goods.

Here is what the concept Taxable looks like:

  • A Taxable item,
    • has a taxRate of 6 percent,
    • has a calculateTax() method.

When implemented in Java, these concepts will appear as classes and one interface. Careful consideration of our Object Oriented Design suggests the following.

Concept Parent Class, Child Class, or Interface?
Goods Parent Class
Food Child Class
Toy Child Class
Book Child Class
Taxable Interface

 

Here is a diagram that shows the classes and the interface. The child classes extend their parent class Goods. This is shown by a solid arrow pointing to the parent class.

The solid arrows show inheritance. The three child classes inherit the display() method.

Two of the classes implement the interface Taxable. This is shown by a dotted arrow pointing to the interface.

The dotted arrows show what a class implements. The Toy and Book classes must implement the calculateTax() method.


Here is the general purpose class Goods. It has two fields - description and price - which are set by its constructor, and a display method - that prints out the current values of these fields (i.e. the current state of the object).

public class Goods {
     String description;
     double price;

 

     public Goods(String des, double pr) {
          description = des;
          price = pr;
     }

 

     public void display() {
          System.out.println("item: " + description + " price: " + price);
     }
} 

The child class Food extends its parent class Goods. It uses the keyword super to call the parent class's constructor and the parent's display method.

public class Food extends Goods {
     double calories;

 

     public Food(String des, double pr, double cal) {
          super(String des, pr);
          calories = cal;
     }

 

     public void display() {
          super.display();
          System.out.println("calories: " + calories);
     }
} 

Here is the interface Taxable:

  • A Taxable item :
    • has a taxRate of 6 percent, which should be a double constant.
    • and a calculateTax() method, which should return a double value.

The Taxable interface looks like this:

interface Taxable {
     final double taxRate = 0.06;
     public double calculateTax();
} 

The keyword final makes field taxRate a constant, not a variable (variables are not allowed in interfaces.) In fact, the keyword final can be omitted because the identifier that follows will automatically be a constant because it is declared in an interface; however, for clarity it is best practice to include it. The "= value" cannot be omitted - because taxRate is a constant, it must be set to a value.

The method declaration (in the second line) is public by default, but once again it is best practice to make that absolutely clear by including the keyword 'public'.

 

The Other Classes

Here is a partial definition of Toy. Recall that it:

  • Extends parent class Goods.
  • Adds a variable called 'minimumAge'.
  • Implements the taxable interface.

The constant taxRate is used in the calculateTax() method just as if it had been defined in the Toy class itself. Further, it can be used in methods of the class other than those listed in the interface.

public class Toy extends Goods implements Taxable {
     int minimumAge;

 

     public Toy(String des, double pr, int min) {
          super(des, pr);
          minimumAge = min ;
     }

 

     public void display() {
          super.display();
          System.out.println("minimum age: " + minimumAge);
     }

 

     public double calculateTax() {
          return price * taxRate;
     }
} 

The calculateTax() method must be made public.

There is one remaining class in our example, Book, which looks like this:

  • Extends its parent class Goods.
  • Adds a variable called 'author'.
  • Implements the interface taxable.
 public class Book extends Goods implements Taxable {
     String author;

 

     public Book(String des, double pr, String auth) {
          super(des, pr);
          author = auth;
     }

 

     public void display() {
          super.display() ;
          System.out.println("author: " + author);
     }

 

     public double calculateTax() {
          return price * taxRate;
     }
} 

Here is a small test program :

public class Store {
     public static void main(String[] args) {
          Goods gd = new Goods("bubble bath", 1.40);
          Food  fd = new Food ("dofu", 4.45, 1500);
          Book  bk = new Book ("Emma", 24.95, "Austin");
          Toy   ty = new Toy  ("Lego", 54.45, 8);

 

          gd.display();
          fd.display();
          ty.display();
          System.out.println("Tax is: " + ty.calculateTax() + "\n");
          bk.display();
          System.out.println("Tax is: " + bk.calculateTax() + "\n");
     }
} 

The calculateTax() method is only used with objects whose class implements the interface taxable.

Here is a diagram that shows the classes and their objects :

In the picture, clouds represent classes. Solid arrows connect child classes to parent classes. The dotted rectangle represents the interface; a dotted arrow shows which classes implement it. Rectangles represent objects. Arrows with a square head connect an object to its class.

Here is a modified testing program that uses an array.

public class Store {
     public static void main(String[] args) {
          Goods[] inventory = new Goods[4];
          inventory[0] = new Goods("bubble bath", 1.40);
          inventory[1] = new Food("dofu", 4.45, 1500);
          inventory[2] = new Book("Emma", 24.95, "Austin");
          inventory[3] = new Toy("Lego", 54.45, 8);

 

          inventory[0].display();
          inventory[1].display();
          inventory[2].display();
          inventory[3].display();
     }
} 

Since each child class is a (type of) Goods, an array of type Goods can be used to hold the instances of the child classes of class Goods.

 

Interface as a Type

An interface can be used as a data type for a reference variable. Since Toy and Book implement Taxable, they can both be used with a reference variable of type Taxable:

  public static void main(String[] args) {
       Taxable item1 = new Book("Emma", 24.95, "Austin");
       Taxable item2 = new Toy("Lego", 54.45, 8);
       System.out.println("Tax on item 1 " + item1.calculateTax());
       System.out.println("Tax on item 2 " + item2.calculateTax());
  } 

The compiler has been told in the interface that all Taxable objects will have a calculateTax() method, so that method can be used with the variables.

 

Type Casts

When you use a variable of type Taxable you are asking to use the "taxable" aspect of the object.

Many different kinds of object might be referred to by the variable. In a larger program there may be Taxable classes that are not Goods. The compiler can only use the methods it knows that the object must have—those in the interface.

However, you can use a typecast to tell the compiler that in a particular statement in the program the variable will refer to an object of a specific class. For example:

  public static void main(String[] args) {
       Taxable item1 = new Book("Emma", 24.95, "Austin");
       System.out.println("Tax on item 1 " + item1.calculateTax());
       ((Book)item1).display();
  } 

This program is not very sensibly written, because variable item1 is of type Book and everything would work without the need for the type cast. But in programs with more complicated logic such class casts are sometimes needed.

A class cast (also called 'typecast') is necessary to tell the compiler that the variable tax in the following case contains a Book object:

  public static void main(String[] args) {
       Book  book;
       Taxable tax = new Book("Emma", 24.95, "Austin");
       book = (Book)tax;
       book.display();
       System.out.println("Tax on item 1 " + book.calculateTax());
  } 

Here is an alternative test program, with different type casts.

public static void main(String[] args) {
     Goods toy;
     Taxable tax = new Toy("Robot", 1.49, 6);
     toy = (Toy)tax;
     toy.display();
     System.out.println("Tax: " + ((Taxable)toy).calculateTax());
} 

The first type cast must cast variable tax to type Goods (or an ancestor). The second must cast variable toy to Taxable or to a class that implements interface Taxable.

Here is another possible way to achieve the same result :

  public static void main(String[] args) {
       Goods goods;
       Taxable tax = new Toy("Robot", 1.49, 6);
       goods = (Goods)tax;
       goods.display();
       System.out.println("Tax: " + ((Toy)goods).calculateTax());
  }

 

Extending an interface

An interface can extend another interface - but not extend a class!

For example :

public interface ExciseTaxable extends Taxable {
     double extraTax = 0.02;
     double calculateExciseTax();
} 

A complex hierarchy of interfaces can be constructed using this feature.

 

Download and run ...

An improved version of the example project is available as a TJI project in the 'Resources' page of our web site.

Simply download the zip file and then choose 'Project Import' from the 'Project' menu. Select the zip file and the project will be imported and setup automatically. Now simply click on the 'Run' button to compile and run.

 

Note : This document was partly based on material written by Bradley Kjell of the Central Connecticut State University.

Return to index