abstract class

 

Classes in a hierarchy are related by the "is-a" relationship. For example, a Nissan is-a Automobile, and a Sentra is-a Nissan. This chapter discusses how reference variables are used for objects from different classes within a hierarchy. Another subject is the idea of an abstract class---a class that cannot be instantiated, but can be the parent of other classes

 

 

Greeting Card Hierarchy

The example of this chapter is a hierarchy of greeting cards types. The parent class is Card, and its children classes are Valentine, Holiday, and Birthday.

A card object will have a greeting() method that writes out a greeting. Each type of card contains an appropriate greeting; the Holiday card says "Season's Greetings," the Birthday card says "Happy Birthday," and the Valentine cards says "Love and Kisses."

In this example, an object must be an instance of one of the three child types: Valentine, Holiday, and Birthday. There will be no such thing as an object that is merely a "Card." The Card class represents the abstract concept of "Card." All actual card objects must be more specific.

 

 

 

 

 

Abstract Class

For this example, all card objects are one of the three types (Valentine, Holiday, or Birthday) and the parent class Card is used only to group them into a hierarchy. There will never be an object that is just a card. This is useful to do, just as a drug store will have all its various greeting cards in one display, arranged into several categories.

 

An abstract class in Java is a class that is never instantiated. Its purpose is to be a parent to several related classes. The child classes will inherit from the abstract parent class.

 

In hierarchy drawings (such as on the previous page), abstract classes are often drawn with dotted lines. An abstract class is defined like this:

 

abstract class ClassName
{

   . . . . .  // definitions of methods and variables

}

Access modifiers such as public can be placed before abstract. Even though it can not be instantiated, an abstract class can define methods and variables that children classes inherit.

 

 

 

Abstract Methods

In this example implementation, each card class will have its own version of the greeting() method. Since each class has a greeting(), but each one is implemented differently, it is useful to put an abstract greeting() method in the parent class. This says that each child inherits the "idea" of greeting(), but each implementation is different. Here is the class definition of the abstract class Card:

 

abstract class Card
{
  String recipient;                 // name of who gets the card
  public abstract void greeting();  // abstract greeting() method
}

This is a complete definition of this abstract class. Notice the abstract method. Abstract classes can (but don't have to) contain abstract methods. Also, an abstract class can contain non-abstract methods, which will be inherited by the children.

An abstract method has no body. (It has no statements.) It declares an access modifier, return type, and method signature followed by a semicolon. A non-abstract child class inherits the abstract method and must define a non-abstract method that matches the abstract method.

An abstract child of an abstract parent does not have to define non-abstract methods for the abstract signatures it inherits.

 

 

 

Holiday

Here is a class definition for class Holiday. It is a non-abstract child of an abstract parent:

 

class Holiday extends Card
{
  public Holiday( String r )
  {
    recipient = r;
  }

  public void greeting()
  {
    System.out.println("Dear " + recipient + ",\n");
    System.out.println("Season's Greetings!\n\n");
  }
}

The class Holiday is not an abstract class; objects can be instantiated from it.

 

 

 

Not Everything in an abstract Class is abstract

abstract class Card
{
  String recipient;
  public abstract void greeting();
}

class Holiday extends Card
{
  public Holiday( String r )
  {
    recipient = r;
  }

  public void greeting()
  {
    System.out.println("Dear " + recipient + ",\n");
    System.out.println("Season's Greetings!\n\n");
  }
}

public class CardTester
{
  public static void main ( String[] args )
  {
    Holiday hol = new Holiday("Santa");
    hol.greeting();
  }
}

 

Not everything defined in an abstract classes needs to be abstract. The variable recipient is defined in Card and inherited in the usual way. However, if a class contains even one abstract method, then the class itself has to be declared to be abstract. At left is a program to test the two classes.

This is a complete runable program. I imagine the urge to copy it to NotePad and get it running is irresistable. Remember to call the file "CardTester.java" .


 

 

Advantage of Abstract Classes

Here is a sample run of the program:

Dear Santa,

Season's Greetings!

 

The advantage of using an abstract class is that you can group several related classes together as siblings, even though none is the parent of the others. Grouping classes together is important in keeping a program organized and understandable. The picture shows this program after its object has been constructed.


It would be nice to deal some other cards. Here is a skeleton for the Birthday class:

 

class Birthday extends ______________ 
{
  int age;

  public ______________ ( String r, int years )
  {
    recipient = r;
    age = years;
  }

  public void greeting()
  {
    System.out.println("Dear " + recipient + ",\n");
    System.out.println("Happy " + _______ + "th Birthday\n\n");
  }
}
The missing parts have been filled in, below.

Valentine Card

Here is the complete birthday card:

class Birthday extends Card 
{
  int age;

  public Birthday ( String r, int years )
  {
    recipient = r;
    age = years;
  }

  public void greeting()
  {
    System.out.println("Dear " + recipient + ",\n");
    System.out.println("Happy " + age + "th Birthday\n\n");
  }
}

The Valentine class is much the same, except for some added passion:

class Valentine extends Card 
{
  int kisses;

  public Valentine ( String r, int k )
  {
    recipient = r;
    kisses    = k;
  }

  public void greeting()
  {
    System.out.println("Dear " + recipient + ",\n");
    System.out.println("Love and Kisses,\n");
    for ( int j=0; j<kisses; j++ )
      System.out.print("X");
    System.out.println("\n\n");
  }
}

 

Complete Program

Here is a complete program with all three card classes and objects of each type. If you were deficient in greeting cards this year, you might wish to copy this to NotePad and run it a few times.

 

import java.io.*;

abstract class Card
{
  String recipient;
  public abstract void greeting();
}

class Holiday extends Card
{
  public Holiday( String r )
  {
    recipient = r;
  }

  public void greeting()
  {
    System.out.println("Dear " + recipient + ",\n");
    System.out.println("Season's Greetings!\n\n");
  }
}

class Birthday extends Card
{
  int age;

  public Birthday ( String r, int years )
  {
    recipient = r;
    age = years;
  }

  public void greeting()
  {
    System.out.println("Dear " + recipient + ",\n");
    System.out.println("Happy " + age + "th Birthday\n\n");
  }
}

class Valentine extends Card
{
  int kisses;

  public Valentine ( String r, int k )
  {
    recipient = r;
    kisses    = k;
  }

  public void greeting()
  {
    System.out.println("Dear " + recipient + ",\n");
    System.out.println("Love and Kisses,\n");
    for ( int j=0; j < kisses; j++ )
      System.out.print("X");
    System.out.println("\n\n");
  }
}

public class CardTester
{
  public static void main ( String[] args ) throws IOException
  {
    String me;
    BufferedReader input = new BufferedReader( new InputStreamReader(System.in) );
    System.out.println("Your name:");
    me = input.readLine();

    Holiday   hol = new Holiday( me );
    hol.greeting();

    Birthday  bd  = new Birthday( me, 21 );
    bd.greeting();

    Valentine val = new Valentine( me, 7 );
    val.greeting();


  }
}

 

Objects of each Class

By using hierarchical organization and inheritance it is easy to add many more card classes and to create a well organized program. This was unthinkable not too many years ago. Here is a sample run of this program:

Your name:
Sue
Dear Sue,

Season's Greetings!

Dear Sue,

Happy 21th Birthday

Dear Sue,

Love and Kisses,

XXXXXXX

 

When the main() method has constructed its three objects, the situation is as in the picture. There are three classes that can be instantiated, and one object of each class has been instantiated. Of course, as many objects as you need of each type (except Card) can be instantiated.

 

 

Can't Instantiate an Abstract Class

The program can't do the following:

 

   . . . .

  public static void main ( String[] args ) throws IOException
  {
     . . . . 

    Card card = new Card() ;        // can't instantiate abstract class
    card.greeting() ;

     . . . .
  }

Because Card is an abstract class, the compiler would say this is a syntax error. However, the following is OK:

 

   . . . .

  public static void main ( String[] args ) throws IOException
  {
     . . . . 

    Card card = new Valentine( "Joe", 14 ) ;      // a Valentine is-a Card
    card.greeting() ;

     . . . .
  }

It is OK to save a reference to a Valentine object in a reference variable of type Card because Valentine is-a Card. You can think of the reference variable card as being a card rack designed to hold any specific instance of a Card.

 

 

 

Using Parent Class Reference Variables

A reference variable of class "C" can be used with any object that is related by inheritance to class "C". For example, a Card reference variable card2 can hold a reference to a Holiday object, a Valentine object, or a Birthday object. Usually, references to a parent class are used to hold children objects.

Important Point:

When a method is invoked, it is the class of the object (not of the variable) that determines which method is run.

For example:

Card card = new Valentine( "Joe", 14 ) ;
card.greeting();

Card card2 = new Holiday( "Bob" ) ; 
card2.greeting();

Card card3 = new Birthday( "Emily", 12 ) ; 
card3.greeting();

This will run the greeting() method for a Valentine, then it will run the greeting() method for a Holiday, then it will run the greeting() method for a Birthday. The type of the object in each case determines which version of the method is run