2.17 Abstract Classes2.16 Final Methods and Classes2 Java with Caffeine2.18 Frameworks

2.17 Abstract Classes

Classes may serve two purposes:

  1. as templates for instantiating objects in new calls;
  2. as parent classes for other classes by extends declarations.
The classes we have seen up to now served both purposes; however sometimes one wishes to declare a class that is only used for the second purpose.

For instance, let us assume that we want to write a generic method printNice which prints an object with a nice header line before and after the object contents. However, to be able to print the object contents, the object must provide a string representation of itself. We can express this by the fact that printNice operates on objects of type (respectively subtype of) Printable which provide via a method getString a string representation of themselves:

   static void printNice(Printable o)
   {
     System.out.println("-- begin object ------------------ ");
     System.out.println(o.getString());
     System.out.println("-- end object -------------------- ");
   }

The class Printable can be declared as

   abstract class Printable
   {
     abstract String getString();
   }

The method getString is declared with the keyword abstract which says that the method does not contain an implementation (i.e., a body) in this class. Since the class Printable contains an abstract method, it must be also declared as abstract. Such an abstract class does not contain implementation for some of its methods, it cannot be used for instantiating objects in new calls; it can be only used for inheritance by other classes.

If a subclass of Printable provides implementations for all the abstract methods of the superclass, it is itself not abstract any more and can be used for instantiation. We may thus define a non-abstract subclass MyInteger of Printable as follows:

   class MyInteger extends Printable
   {
     int i;
     MyInteger(int i) { this.i = i; }
 
     String getString() 
     {
        return Integer.toString(i);
     }
   }

Then we may call

   MyInteger i = new MyInteger(7);
   printNice(i);

where printNice invokes the getString method declared in MyInteger. We may also write above example as

   Printable i = new MyInteger(7);
   printNice(i);

where we immediately forget that i is of type MyInteger but treat it as an object of type Printable. Thus we cannot create objects of type Printable (an abstract class cannot be the dynamic type of a variable) but we can declare variables and parameters of this type (an abstract class can be the static type of a variable).


© Wolfgang Schreiner; February 3, 2005

2.17 Abstract Classes2.16 Final Methods and Classes2 Java with Caffeine2.18 Frameworks