URL: http://www.elementkjournals.com/vjp/s_vjp/9802/vjp9826.htm 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