February 1998

Extensibility and reusability: Abstract classes and interfaces
by Qusay H. Mahmoud 

You can use both abstract classes and interfaces to define functionality 
shared by a group of objects. However, sometimes we're not sure whether we 
should share implementation or maintain independent implementations. Then, 
we must choose between an abstract class and an interface. In this 
article, we'll introduce you to abstract classes and interfaces, then 
we'll show you the differences between them and the benefits of each. 

Abstract classes
An abstract class is a basic class that's incomplete. It's called abstract 
because it has no direct instances--that is, you can't directly create 
(with the new operator) any object from an abstract class. However, 
descendant classes (also known as concrete classes) may have direct 
instances. Only abstract classes can have abstract methods--that is, 
methods that are declared but have no implementation. As an example of an 
abstract class, consider the following: 

abstract class Shapes {
   int x = 0;
   int y = 0;
   void move (int dx, int dy) {
      x += dx; 
      y += dy;
      draw();
   }

   abstract void draw(Graphics g);
}

In the previous example, we declare the class Shapes as abstract because 
it contains a declaration of an abstract method named draw(). Since Shapes 
is declared as an abstract class, you can create no direct instances from 
this class. Thus, a compile-time error occurs if you try to create an 
instance of the abstract class Shapes. So, a statement such as 
Shapes s = new Shapes();

would result in a compile-time error. Also, if you attempt to instantiate 
an abstract class using the newInstance method, java.lang.Class will cause 
an exception (InstantiationException) to be thrown. 
It's important not to mix abstract classes with final classes. A class is 
declared final if no subclasses are desired. Also note that if a class is 
declared final, it can't be declared abstract; if it is, a compile-time 
error occurs. The same error occurs if a class attempts to extend a final 
class. 

Inheritance
In most object-oriented languages, classes can be defined in terms of 
other classes, and objects are actually instances of classes. Classes can 
be organized in a hierarchy. A subclass inherits attributes from a 
superclass at a higher level in the hierarchy. Also, a subclass can add 
more variables and methods to the ones inherited from the superclass, as 
well as override inherited methods by providing specialized 
implementations for those methods. 
In Java, classes can have only one superclass; that is to say, Java has 
support only for single inheritance. However, note that a class may 
implement multiple interfaces. As an example, we'll inherit from the above 
abstract class named Shapes. 

class Circle extends Shapes {
    public void draw(Graphics g) {
      g.drawOval(someParameters);
    }
}

The class Circle above inherits the move() method from Shapes and provides 
implementation for it. The Circle class must provide implementation for 
the draw() method. Now, you can create instances from the Circle class. We 
mentioned above that you can't create instances from an abstract class. 
However, note that you can initialize a Shapes variable with a reference 
to any subclass of Shapes. Since the class Circle isn't abstract, the 
statement 
Shapes s = new Circle();

is correct. This simple statement will execute the default constructor of 
the abstract class Shapes and field initializers for x and y of Shapes. 

Interfaces
An interface in Java consists of a series of declarations that are subject 
to the following two restrictions: 
Method declarations must not include implementation code. 
Variable declarations can only have constant initializations.
interface Shape{
   int x = 0;
   int y = 0;
  
   void move(int dx, int dy);
}

In the above example, Shape is the name of the interface, and move is a 
method declared inside the Shape interface. Note that every interface is 
implicitly abstract, so the use of the abstract modifier is obsolete. 
We've also mentioned that variable declarations in an interface can only 
have constant initializers, but now you may wonder why the variables x and 
y in the interface Shape aren't constant (using the public static final 
modifiers). The fact is, every field declared in the body of an interface 
is implicitly public static final. Thus, specifying any of these modifiers 
for such fields is considered to be redundant and discouraged. 

The whole purpose of an interface is to identify a common set of methods 
and constants for the group of classes that implements the interface. When 
a class implements one or more interfaces, the implemented interface(s) is 
(are) identified by the implement clause of the class declaration. For 
example, the following Triangle class implements the Shape interface: 

class Triangle  implements Shape {
   void move(int dx, int dy){
    // provide implementation here
   }
}

When to use what
Interfaces are actually more useful than they might first appear. They 
take us from writing one-shot classes to writing extensible packages and 
frameworks of classes. If a set of classes happens to offer the same 
service, then the classes can share the same interface. As an example, 
suppose we write an application for manipulating (drawing, moving, 
removing) different shapes on the screen. For simplicity, assume we want 
to draw three shapes: circle, rectangle, and triangle. 
A one-shot job may be to write an independent class for each shape and 
have all the operations that can be performed on that shape encapsulated 
within the corresponding class. However, if we decide to add a new shape, 
then we must write a new class and modify the main application where we 
choose what to draw. Consequently, this approach is neither reusable nor 
extensible. 

Knowing that the three shapes share some common characteristics (for 
instance, they can be drawn, moved, and removed), we can have an interface 
that all shapes share. This interface can be as simple as the following: 

interface Shapes {
   void draw(Graphics g);
   void move(int offsetX, int offsetY);
   void erase(); // paint with background color
}

The interface Shapes declares three operations: draw, move, and erase. 
Now, each shape can implement this interface. For example, the Circle 
shape can implement the interface as follows: 
class Circle implements Shapes {
   public int x, y, r;
   
   public Circle(int x1, int y1, int radius) {  
     // constructor
      x = x1;
      y = y1;
      radius = r;
   }

   public void draw(Graphics g) {
      g.drawOval(x-r, y-r, 2*r, 2*r);
   }

   public void move(int oldX, int oldY) {
      x += oldX;
      y += oldY;
   }

   public void erase() {
     // paint the region with background color
   }
}

We can do the same for the other two shapes, namely, Triangle and 
Rectangle. 
Of course, we could achieve the same objective by using an abstract class 
instead of an interface. In this case, it doesn't really matter whether we 
use an interface or an abstract class. Interfaces, however, are a very 
useful tool for remote method invocations. For example, if you're familiar 
with Java RMI (Remote Method Invocation), you know that the first order of 
business in writing an RMI application is to define a public remote 
interface. Such an interface for an arithmetic server might resemble the 
following: 

public interface MathServer extends 
	java.rmi.Remote {
    	int[] Add(int a[], int b[]) throws 
	java.rmi.RemoteException;
    // other methods
}

The whole purpose of using the interface is so that a programmer for a 
client of this interface can tell what operations the arithmetic server 
provides and how to use them--just by looking at the interface. An 
abstract class isn't a good choice in this example, since an abstract 
class may have some non-abstract methods (i.e., methods with 
implementations). Including non-abstract methods allows the client to look 
at those implementations, which is a situation we may want to protect 
against. 

Multiple inheritance
Since Java doesn't support multiple inheritance, it actually avoids a lot 
of troubles surrounding ambiguities. In essence, however, Java replaces 
multiple inheritance with conformance to interfaces. While a class in Java 
can't inherit from more than one base class, it is allowed to implement 
multiple interfaces. This capability lets you achieve the same goals as 
multiple inheritance, but without the ambiguities. 
Suppose, for example, that there's a class named Calculate. This class 
provides methods for calculating areas and other parameters for various 
shapes. If we did inherit from this class, then we could write something 
like this: 

class Circle extends Calculate implements Shapes {
//
// provide implementation for methods and override others 
}

If we don't have interfaces, then we won't be able to simulate multiple 
inheritance, since inheriting from multiple base classes isn't allowed. 
One last thing to note is that interfaces can actually inherit from each 
other, as do classes. 

Conclusion
Abstract classes and interfaces are alike in the sense that neither is 
directly instantiable via the new operator. Both are vital tools for 
writing extensible packages and frameworks of classes. 

Warning: Failed opening 'vjp/includes/vjpbottom.htm' for inclusion 
(include_path='.:/web/zdj/pages:/web/zdj/include:/web/zdj/security:/web/zdj/pages/content:/web/zdj/include/includes') 
in /web/zdj/pages/vjp/s_vjp/9802/vjp9826.htm on line 273