Chapter 12: Inheritance, Interfaces and Polymorphism

In the mid-1960s, two researchers at the Norwegian Computing Center in Oslo, Ole-Johan Dahl and Kristen Nygaard, were writing programs that imitated real systems: ships arriving at a port, people forming queues, machines breaking down and being repaired. The programs kept growing awkward. A ferry, a cargo ship and a fishing boat all had a name, a position and a speed, and all of them moved. Yet each also carried something the others did not. Writing three separate descriptions meant writing the same movement code three times — and correcting a mistake in it three times.

Their answer, published in the language Simula 67, was to allow one class to be declared as a special kind of another. The shared description was written once. Each particular kind then said, in effect, “I am a vessel, and in addition I have this.” When the shared description was corrected, every kind built on it was corrected along with it.

That single idea — one class extending another — is the idea Java took up, and it is the subject of this chapter. It arrives with three questions its designers had to settle, and so will you: what a subclass is allowed to touch, what it is allowed to change, and how a running program decides which version of a method to carry out.

The shape such a program takes is drawn in Fig. 12.0-1.

Diagram

Fig. 12.0-1 – one box labelled “Vessel” at the top listing the attributes name, position and speed and the method move(); three boxes below it labelled “Ferry”, “CargoShip” and “FishingBoat”, each listing one attribute of its own (passengers, tonnage, netSize); an upward arrow from each of the three boxes to the Vessel box, every arrow labelled “extends”

NoteCuriosity Corner

Q1. If a class keeps some of its data private, how can a class built on top of it ever use that data? Q2. A subclass inherits the methods of its superclass. Why does it not inherit the constructor as well? Q3. Two objects are handled by exactly the same line of code, yet they print different things. How does the program decide what to do? Q4. What use is a class if you are forbidden to create even a single object of it? Q5. Java refuses to let a class extend two classes at once. So how can one class take on behaviour described in two different places?

By the end of this chapter you will be able to answer each of these questions.

12.1 Inheritance: Extending a Class Instead of Rewriting It

A class, as you learnt in Class XI, is a description: it states what data an object of that kind holds and what that object can do. So far every class you have written has been a description standing on its own. Nothing connected one class to another.

Real descriptions are rarely so separate. A cash memo and a delivery note are both bills. A savings account and a current account are both accounts. In each pair the two things share a great deal and differ in a little. A programming language that can only write descriptions from scratch forces you to repeat the shared part, once for every kind.

Java lets you say instead that one class is a particular kind of another. The shared description is written once, in one class, and the specialised class states only what it adds or alters. That mechanism is called inheritance, and this section builds it from the problem upwards.

12.1.1 The Problem That Inheritance Solves

Consider the register of a school library. Every item on the shelves — a book, a magazine, an atlas — is given an accession number when it is bought, and every item has a title. Whatever the item, the librarian must be able to display these two details.

Suppose you write one class for books and another for magazines. The book class needs a title, an accession number, an author and a method to display the details. The magazine class needs a title, an accession number, the month of the issue and a method to display the details. Two of the three variables, and almost all of the display code, are identical in the two classes.

That duplication is drawn in Fig. 12.1-1. It is not merely untidy; it is dangerous. Suppose the school later decides that every displayed record must also show the shelf on which the item stands. You must now change both classes. If you change one and forget the other, the program still compiles and still runs, and the mistake shows up only when somebody notices that magazines are printing one line less than books.

Diagram

Fig. 12.1-1 – two boxes side by side, “class Book” on the left and “class Magazine” on the right; each box lists the variables title and accNo and the method showItem(), and these three shaded to mark them as repeated; below the shading each box lists one unshaded member of its own — author in Book, month in Magazine; a caption arrow between the two shaded regions labelled “written twice, corrected twice”

The problem, stated generally, is this: two descriptions overlap, and the language gives you no way to write the overlap once. That is exactly the gap inheritance fills.

12.1.2 Superclass and Derived Class: the extends Keyword

The method of repair is straightforward. Pull the shared part out into a class of its own — call it LibraryItem — and then declare the class Book as a particular kind of LibraryItem. The keyword that states this relationship is extends.

class Book extends LibraryItem
{
}

That one line does a great deal. Every non-private variable and every non-private method of LibraryItem becomes available inside Book and on every object of Book, without being written again.

NoteDefinition

Inheritance is the mechanism by which one class acquires the data members and member methods of another class, so that the acquiring class may use them as though they had been declared in it, and may add further members of its own.

The class whose description is acquired is the superclass; it is also called the base class or parent class. The class that acquires it is the derived class; it is also called the subclass or child class. In the declaration above, LibraryItem is the superclass and Book is the derived class. Note the direction carefully: the arrow of inheritance runs from the derived class upward to the superclass, because it is the derived class that names the other, never the reverse.

Table 12.1 – Superclass compared with derived class

Feature Superclass (base class) Derived class (subclass)
What it holds the description common to a whole group of kinds one specialised kind within that group
How it is written declared on its own, naming no other class declared with extends, naming its superclass
Access to the other’s members cannot use the members added by the derived class can use the non-private members of its superclass
How many one class may serve as superclass to any number of classes one class may extend exactly one superclass
Objects an object of it holds only its own members an object of it holds the inherited members and the added ones together

The last row is the one students most often get backwards. A Book object is not a small object holding only an author; it holds a title and an accession number as well, because a book is a library item. Only when this is clear does the program below read correctly.

recording a library item and, for a book, its author as well Problem: Store the accession number and title of a library item in a superclass, and the author’s name in a class derived from it. Display all three details of one book. The values are fixed inside main(); no input is read.

// Purpose: to show a derived class using the members it inherits
// from its superclass along with a member of its own.

class LibraryItem
{
    String title;
    int accNo;

    void setItem(String t, int a)
    {
        title = t;
        accNo = a;
    }

    void showItem()
    {
        System.out.println("Accession number: " + accNo);
        System.out.println("Title: " + title);
    }
}

class Book extends LibraryItem
{
    String author;

    void setAuthor(String au)
    {
        author = au;
    }

    void showBook()
    {
        showItem();
        System.out.println("Author: " + author);
    }
}

class LibraryDemo
{
    public static void main(String args[])
    {
        Book b = new Book();
        b.setItem("Introduction to Algebra", 1024);
        b.setAuthor("S. Venkatesan");
        b.showBook();
    }
}

Sample output:

Accession number: 1024
Title: Introduction to Algebra
Author: S. Venkatesan

Variable description:

[Table:] Table 12.2 – variables of the library program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | title | String | stores the title of the library item | | accNo | int | stores the accession number of the library item | | author | String | stores the author’s name, added by class Book | | t | String | formal argument of setItem() receiving the title | | a | int | formal argument of setItem() receiving the accession number | | au | String | formal argument of setAuthor() receiving the author’s name | | b | Book | object through which the inherited and the added members are used |

Notes: showBook() does not print the accession number and title itself; it calls showItem(), the method it inherited. This is the shape you should aim for. The derived class adds what is new and delegates what is common, so that a later change to showItem() — adding a shelf number, say — reaches books and every other kind of item at once. Note also that b.setItem(...) is written on a Book object although setItem() was declared in LibraryItem; to the outside world an inherited method is simply one of the object’s methods.

Q. The program never creates an object of LibraryItem. Does that make the superclass useless?

A. No. Its members are present inside every Book object that is created. A superclass earns its place by being inherited, not by being instantiated — and in Section 12.7 you will meet classes that are forbidden to be instantiated at all.

12.1.3 What a Derived Class Receives and What It Adds

It helps to picture a Book object as being built in two layers, as in Fig. 12.1-2: the layer described by the superclass, and the layer added by the derived class. The object is one object, not two; the layers only record where each member’s description was written.

Diagram

Fig. 12.1-2 – a single rounded box labelled “one Book object”; inside it an upper compartment labelled “inherited from LibraryItem” containing title and accNo, and a lower compartment labelled “added by Book” containing author; to the right, a list of the methods callable on the object — setItem(), showItem(), setAuthor(), showBook() — with the first two tagged “inherited”

Three things pass from superclass to derived class, and three do not. A derived class inherits the superclass’s instance variables and its member methods, and through them the behaviour they define. It does not inherit the superclass’s constructors, it cannot directly reach the superclass’s private members, and it gains no power to alter the superclass itself. The first of these is taken up in Section 12.3 and the second in Section 12.2.

Within the derived class you are free to add. You may declare new instance variables that the superclass never had, as Book adds author. You may declare new methods, as Book adds setAuthor() and showBook(). And you may declare a method with the same name as one in the superclass, which redefines it — the subject of Section 12.4.

Why this matters: reusability

The practical gain from all this is reusability: code written and tested once is used by many classes without being copied. Three consequences follow, and they are worth stating separately.

First, the program models a real relationship rather than merely storing data. The sentence “a book is a library item” is not a comment; it is a line of Java, and the compiler enforces it.

Second, a correction made in the superclass reaches every derived class automatically. If showItem() is improved, every kind of item improves with it, and no class can be left behind by an oversight.

Third, inheritance is transitive. If ReferenceBook extends Book and Book extends LibraryItem, then a ReferenceBook object holds the members of all three, and title is as available in ReferenceBook as it is in Book.

An honest limitation belongs here too. Inheritance ties the derived class tightly to the superclass: any change in the superclass’s members ripples down to every class beneath it, and a careless change can break code the author of the superclass has never seen. Depth is therefore not a virtue. A hierarchy two or three levels deep is usually easier to reason about than one of eight.

Key in the library program and run it. Then add a class Magazine that extends LibraryItem, gives it a String variable month, a method to set it and a method showMagazine() that calls showItem() before printing the month. Create one Magazine object in main() alongside the Book object and confirm that both print their common details correctly.

12.1.4 Forms of an Inheritance Hierarchy

Once a class may extend a class, several shapes of hierarchy become possible. Java permits some of them and rules out one. The three that Java supports directly are drawn in Fig. 12.1-3.

Diagram

Fig. 12.1-3 – three panels side by side, each of plain boxes joined by upward arrows labelled “extends”. Panel (a) “single”: Book above which sits LibraryItem, one arrow. Panel (b) “hierarchical”: LibraryItem at the top with Book, Magazine and Atlas below it, three arrows converging upward on LibraryItem. Panel (c) “multilevel”: LibraryItem at the top, Book below it, ReferenceBook below Book, two arrows forming a chain

In single inheritance, one derived class extends one superclass. This is the form used in the program of Section 12.1.2 and it is the form all the others are built from.

In hierarchical inheritance, several derived classes extend the same superclass. The library register is naturally of this shape: books, magazines and atlases are all library items, and each writes down only what makes it different.

class LibraryItem
{
    String title;
    int accNo;
}

class Book extends LibraryItem
{
    String author;
}

class Magazine extends LibraryItem
{
    String month;
}

In multilevel inheritance, a derived class is itself extended, so that the chain runs through more than one level. It is also called nested inheritance. Here ReferenceBook is a kind of Book, and a Book is a kind of LibraryItem, so a ReferenceBook object carries the members of all three classes.

class LibraryItem
{
    String title;
    int accNo;
}

class Book extends LibraryItem
{
    String author;
}

class ReferenceBook extends Book
{
    boolean issuable;
}

Notice that each link in that chain is itself a single inheritance. Multilevel inheritance is not a new mechanism; it is single inheritance applied twice.

The form Java does not allow

Multiple inheritance is the form in which one derived class extends two or more superclasses at once. Java does not permit it for classes. You may not write class C extends A, B, and the compiler rejects it outright.

The reason is drawn in Fig. 12.1-4. Suppose classes A and B both contain a method show(), and class C were allowed to extend both. What should c.show() mean? There is no honest answer: the language would either have to guess or force the programmer to disambiguate at every use. Rather than carry that complication, Java restricts a class to one superclass and supplies a different mechanism — the interface — for the cases where behaviour must come from more than one source. That mechanism is the subject of Section 12.8.

Diagram

Fig. 12.1-4 – class A on the upper left and class B on the upper right, each box containing the method show(); class C below and between them, with an upward arrow to A and another to B, both arrows drawn as dashed lines and crossed out; a question mark beside class C labelled “which show()?”; the whole panel captioned “not allowed between classes in Java”

Hybrid inheritance is the name given to a structure that combines more than one of these forms — for instance a hierarchical arrangement in which one of the derived classes is itself extended further. In Java a hybrid structure is built freely out of single, hierarchical and multilevel inheritance; only the multiple-inheritance part of it, where two superclasses meet in one class, must be handled with interfaces instead.

Q. If a class may extend only one class, is the number of classes it can give its members to also limited to one?

A. No. The restriction is on looking upward, not downward. A superclass may be extended by as many classes as you like — that is precisely hierarchical inheritance.

12.1.5 Specialisation, Not Mere Reuse

Inheritance is such a convenient way of borrowing code that it is easy to reach for it whenever one class happens to contain a method another class wants. This is a mistake, and it is worth naming clearly.

Write B extends A only when an object of B genuinely is an object of A — when every sentence true of an A remains true of a B. This is called the is-a relationship, and the test is a sentence in ordinary language: “a reference book is a book” is true, so ReferenceBook extends Book is sound.

Now consider a class Barcode that prints an accession number as a machine-readable strip. It would be convenient to write class Barcode extends LibraryItem, because then the accession number is already there. But “a barcode is a library item” is false. A barcode is not catalogued, not issued and not shelved; it merely refers to something that is. Extending here would give Barcode a title, an author and a display method that make no sense for it, and would leave the program asserting something untrue.

What that situation calls for is the has-a relationship: the Barcode class holds a LibraryItem as one of its variables and uses its methods, without pretending to be one. Holding an object of another class is not inheritance at all; it is ordinary composition, and it carries none of inheritance’s obligations.

The distinction matters more than it may seem. A superclass promises that everything it can do, every class below it can do too. Break that promise — by extending a class purely to raid it for a useful method — and every later reader of the program, and every piece of code written against the superclass, is misled. Reuse is a benefit of inheritance; it is not a reason for it.

12.2 Member Access in a Derived Class

Section 12.1 said that a derived class receives the members of its superclass. That statement was deliberately loose. Inheritance does not hand over everything without condition: the author of the superclass decides, member by member, how far each one may travel.

The instrument of that decision is the access specifier — the keyword written in front of a variable or a method that fixes where in the program that member may be used. Java offers four levels of access, and every member of every class has exactly one of them:

  • private — the most restricted;
  • no specifier at all, called default access;
  • protected;
  • public — the least restricted.

Behind these four lies a principle you met in Class XI. Encapsulation is the practice of keeping an object’s data inside the object and letting the outside world reach it only through the object’s own methods, so that the class alone controls how its data may change. An access specifier is how encapsulation is actually enforced, and inheritance does not suspend it. A derived class is closer to the superclass than an ordinary class is, but it is still on the outside of whatever the superclass chose to hide.

The reach of each level is drawn in Fig. 12.2-1, and the rest of this section takes them one at a time.

Diagram

Fig. 12.2-1 – four nested rectangles, drawn one inside the next. Innermost labelled “the class itself”; around it “other classes of the same package”; around that “derived classes in another package”; outermost “every other class, anywhere”. Four labelled arrows on the left, each starting outside and stopping at the boundary it can reach: private stops at the innermost rectangle, default at the second, protected at the third, public at the outermost

The word package in that figure means a named group of classes kept together, in practice the folder they are compiled in. Unless you deliberately create packages, all the classes of one project — and all the classes of every program in this chapter — belong to a single unnamed package, so the second rectangle of Fig. 12.2-1 quietly contains all of them.

In some other languages, C++ among them, the inheritance itself carries a visibility mode, so that the same superclass can be inherited publicly by one class and privately by another. Java has nothing of the kind. There is no place in class B extends A to write such a mode, and no member ever changes its access by being inherited: each one keeps exactly the access it was given in the superclass.

12.2.1 Private Members of the Superclass

A member declared private may be used only inside the class in which it is declared. That rule has no exception for inheritance. If a superclass declares a variable private, a derived class cannot read it, cannot assign to it and cannot even name it; if a superclass declares a method private, a derived class cannot call it.

This surprises students, because the private variable is undeniably there inside the object. And it is there: a Fare object created from a class that extends Route does hold the ratePerKm declared inside Route. What the derived class lacks is not the storage but the permission.

using a private superclass variable directly in the subclass What students write:

class Fare extends Route
{
    double amount;

    void computeFare()
    {
        amount = distance * ratePerKm;
    }
}

What happens: the program does not run at all. The compiler rejects the line, reporting that ratePerKm has private access in Route. Nothing is produced — no class file, no output.

The fix: ask the superclass for the value instead of taking it.

        amount = distance * getRatePerKm();

getRatePerKm() is a method of Route, so it is inside the class where ratePerKm was declared and may see it; the derived class calls the method rather than touching the data.

Why does a superclass ever hide a member from its own subclasses? Because a variable, once exposed, can be set to anything by anyone who inherits. Suppose ratePerKm must never be negative. So long as it is private and only the superclass’s own methods assign to it, that rule can be checked in one place and cannot be broken. Make it visible to derived classes and the guarantee is gone, since every subclass — including ones written years later by somebody else — may now assign to it freely.

Q. Is a private member of the superclass inherited by the subclass at all?

A. The storage exists in every subclass object, so the member is certainly present. But it is not accessible by name in the subclass, and for the purpose of writing code that is what counts. Say that a private member is present but not accessible, and you will never be confused.

12.2.2 Protected Visibility

Between “only my own class” and “anybody at all” lies the case the superclass author most often wants: my own class, and the classes built on it. That is what protected visibility provides.

NoteDefinition

A member declared protected may be used inside its own class, inside any other class of the same package, and inside any class derived from it, even one placed in a different package. It may not be used by an unrelated class of another package.

For an ordinary Class XII project, where every class sits in the same package, the practical effect is simple: a protected member behaves like a public one inside the project, but a class outside the project can reach it only by inheriting.

class Route
{
    protected double distance;
}

class Fare extends Route
{
    void showDistance()
    {
        System.out.println("Distance in km: " + distance);
    }
}

Here distance is used directly inside Fare, with no method call and no super, exactly as if it had been declared in Fare itself. That is the convenience protected buys.

It buys it at a price, and the price should be stated plainly. Every variable you mark protected becomes part of a promise to every future subclass: you may no longer rename it, change its type or stop maintaining it without breaking classes you did not write. A method marked protected is a far safer promise than a variable, because the method’s body can change while the promise stays the same. The general advice, and it is worth taking, is to keep instance variables private and to expose behaviour rather than data.

12.2.3 Public Members and the Access Comparison

A member declared public may be used from anywhere: inside its class, in any other class, in any package, whether the using class is derived from it or not. A derived class therefore inherits public members with no restriction whatever, and so does every other class that can lay hands on an object.

Public members are how a class states what it offers to the world. In a well-built class the public members are almost all methods — the operations the class promises to perform — while the data behind them stays private.

The whole picture is best held in one table.

Table 12.3 – where a member may be used, for each access specifier; a tick means the member is accessible from that place

Access specifier Its own class Another class, same package Derived class, another package Unrelated class, another package
private yes no no no
default (no specifier) yes yes no no
protected yes yes yes no
public yes yes yes yes

Read the table downwards and you will see that each row adds one place to the row above it; the four levels form a ladder, not four unrelated choices. Read the third column alone and you have the rule for inheritance across packages: a derived class inherits usable protected and public members, and nothing else.

Note the second row carefully, because it is often misstated. A member written with no specifier is not public. It is accessible throughout its own package and nowhere else. Since all your classes normally live in one package, such a member will seem to behave publicly — right up to the day somebody puts a subclass in a different package and the code stops compiling.

12.2.4 Reaching a Private Member through Accessor and Mutator Methods

If a superclass keeps its data private, and a derived class genuinely needs that data, the superclass must supply a door. Two small methods do the job, and they are so common that they have names.

NoteDefinition

An accessor method, commonly called a getter, is a member method of a class that returns the value of one of that class’s own data members. A mutator method, commonly called a setter, is a member method that receives a value and assigns it to one of that class’s own data members.

Both are declared in the superclass, and both are declared public or protected so that a derived class may call them. Because they are members of the superclass, they may touch its private data; because the derived class only calls them, it never touches that data itself. The path is drawn in Fig. 12.2-2.

Diagram

Fig. 12.2-2 – a large box “class Route” containing a small shaded box “private double ratePerKm” and, outside the shading but inside Route, a box “getRatePerKm()” with a short arrow reaching into the shaded box. Below, a separate box “class Fare extends Route” containing “computeFare()”, with an upward arrow labelled “calls” reaching getRatePerKm(). A dashed arrow drawn straight from computeFare() to ratePerKm, crossed out and labelled “not permitted”

The gain is not merely that the value can be fetched. Because every change now passes through a method of the superclass, the superclass can still impose conditions — a setter can reject a negative rate, round a value, or record that a change was made. A protected variable offers no such opportunity, since assignment to it is just assignment.

Q1. If a class keeps some of its data private, how can a class built on top of it ever use that data?

A. Not directly — a private member is present in every subclass object but is not accessible by name in the subclass. The superclass must provide the way in, in the form of an accessor method that returns the value and, where the subclass must change it, a mutator method that receives one. The subclass calls those methods; the private data itself is touched only by the class that declared it.

The program below puts the whole section together. routeName and distance are protected and are used in the derived class by name; ratePerKm is private and is reached only through its accessor.

computing the fare for a bus route from a protected distance and a private rate Problem: A superclass stores the name of a bus route, its length in kilometres and the fare charged per kilometre. A class derived from it computes the fare for the whole route and displays the details. The fare is the distance multiplied by the rate per kilometre. The values are fixed inside main(); no input is read.

// Purpose: to show a derived class using protected members of its superclass
// directly and a private member of the superclass through an accessor method.

class Route
{
    protected String routeName;
    protected double distance;
    private double ratePerKm;

    public void setRoute(String rn, double d, double r)
    {
        routeName = rn;
        distance = d;
        ratePerKm = r;
    }

    public double getRatePerKm()
    {
        return ratePerKm;
    }
}

class Fare extends Route
{
    double amount;

    void computeFare()
    {
        amount = distance * getRatePerKm();
    }

    void showFare()
    {
        System.out.println("Route: " + routeName);
        System.out.println("Distance in km: " + distance);
        System.out.println("Fare in rupees: " + amount);
    }
}

class FareDemo
{
    public static void main(String args[])
    {
        Fare f = new Fare();
        f.setRoute("Bus Stand to School Gate", 12.5, 2.5);
        f.computeFare();
        f.showFare();
    }
}

Sample output:

Route: Bus Stand to School Gate
Distance in km: 12.5
Fare in rupees: 31.25

Variable description:

[Table:] Table 12.4 – variables of the bus fare program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | routeName | String | stores the name of the route; protected, so usable in the derived class | | distance | double | stores the length of the route in kilometres; protected | | ratePerKm | double | stores the fare charged per kilometre; private to Route | | amount | double | stores the computed fare, added by class Fare | | rn, d, r | String, double, double | formal arguments of setRoute() receiving the name, distance and rate | | f | Fare | object through which the fare is set, computed and displayed |

Notes: setRoute() is the single point at which all three values enter the object, which is why it could later be made to reject a negative distance without a line of Fare changing. computeFare() mixes the two styles on one line — distance by name because it is protected, getRatePerKm() by call because the rate is private — and it is worth reading that line slowly, since the difference between the two halves is the whole subject of this section.

Change distance in Route from protected to private, compile, and read the error the compiler gives for computeFare(). Then repair the program by adding an accessor method for the distance, and confirm that the output is unchanged. Which of the two versions would you rather hand to somebody else to extend, and why?

12.3 Constructors in an Inheritance Chain

An object of a derived class holds two sets of variables: those described by its superclass and those added by itself. Section 12.2 dealt with who may use them. This section deals with an earlier question — who gives them their first values.

Recall from Class XI that a constructor is a member method with the same name as its class and no return type, not even void, which is executed automatically when an object of that class is created and whose usual work is to initialise the data members. A constructor that takes no arguments is a no-argument constructor; one that takes arguments is a parameterised constructor, and a class may have several, distinguished by their argument lists.

The awkwardness is this. The superclass’s variables belong to the superclass and are often private to it; only the superclass’s own constructor is in a position to set them. Yet it is a derived class object that is being created, so it is the derived class’s constructor that runs. Something must connect the two, and that something is the keyword super.

12.3.1 Why a Constructor Is Not Inherited

Every other kind of member travels down the hierarchy. A constructor does not. Two reasons, one mechanical and one about meaning, make this unavoidable.

The mechanical reason lies in the name. A constructor must carry the name of its own class. The constructor written inside Vehicle is named Vehicle, and inside a class Bus a method named Vehicle is not a constructor at all — it is just a method with a return type missing, which the compiler will reject. There is simply no way for Vehicle(...) to arrive in Bus and still be a constructor.

The reason about meaning is stronger. A constructor’s job is to leave an object of its class fully and correctly initialised. Vehicle’s constructor knows nothing of seats or route, because those variables did not exist when it was written. If it were inherited and used to build a SchoolBus, it would hand back a half-built object and report success. A class must take responsibility for initialising the members it declares, and only it can.

Q2. A subclass inherits the methods of its superclass. Why does it not inherit the constructor as well?

A. Because a constructor is named after its own class, so a superclass constructor could never serve as a constructor of the subclass; and because a constructor exists to initialise the members its own class declares, and it knows nothing of the members the subclass adds. The subclass writes its own constructor and asks the superclass constructor to complete the inherited part on its behalf, using super.

One related rule from Class XI is worth restating precisely, because it is often stated loosely. If a class declares no constructor of its own, the compiler supplies one that takes no arguments and does nothing beyond starting the superclass part; that supplied one is called the default constructor. The moment a class declares any constructor at all — even a parameterised one — the compiler supplies nothing. A class with only a parameterised constructor therefore has no no-argument constructor, and that single fact causes most of the errors in the next subsection.

12.3.2 Invoking the Superclass Constructor with super

Inside a constructor of the derived class, the statement

super(actual arguments);

calls the constructor of the immediate superclass whose parameter list matches those arguments. Written with brackets in this way, super is a call to a constructor, not a reference to a member; the other use of the keyword, super.method(), belongs to Section 12.4 and is a different thing entirely.

NoteDefinition

super(...) is a statement usable only inside a constructor, which invokes a constructor of the immediate superclass so that the inherited part of the object being created is initialised before the rest of the derived class’s constructor runs.

Four rules govern it, and all four are enforced by the compiler.

  1. If super(...) is written, it must be the very first statement of the constructor. Nothing, not even an assignment, may precede it.
  2. Its arguments must match some constructor of the immediate superclass in number and type.
  3. If you do not write it, the compiler silently inserts super(); — a call to the superclass’s no-argument constructor — as the first statement.
  4. Consequently, if the superclass has no no-argument constructor and you omit super(...), the program does not compile.

Rule 3 explains why constructors seemed to need no attention until now: in every hierarchy where each class has a no-argument constructor, the chaining happens without a word being written. Rule 4 explains the error that appears the moment a superclass is given a parameterised constructor.

omitting super(...) when the superclass has only a parameterised constructor What students write:

class Bus extends Vehicle
{
    int seats;

    Bus(String r, int s)
    {
        regNo = r;
        seats = s;
    }
}

What happens: the compiler inserts super(); before the first line and then looks for a no-argument constructor in Vehicle. Vehicle declares only Vehicle(String), so no such constructor exists and compilation fails at the opening line of Bus(String, int), with the message pointing at a constructor that cannot be found. The error is reported on a line the student did not write, which is what makes it puzzling.

The fix: pass the value up instead of assigning it directly.

    Bus(String r, int s)
    {
        super(r);
        seats = s;
    }

The superclass now initialises the member it declared, which is the only class entitled to guarantee that it was done properly.

Note that the second version works even if regNo is private in Vehicle, while the first version would fail twice over. Passing values upward through super(...) is therefore not merely the correct style; it is often the only style available.

12.3.3 The Order in Which Constructors Run

Because super(...) stands first, a chain of constructors is entered from the bottom and executed from the top. Creating a SchoolBus enters SchoolBus’s constructor, which immediately hands control to Bus’s, which immediately hands control to Vehicle’s. Vehicle’s body is the first body that actually runs to completion; control then unwinds, and each constructor finishes the work it had suspended. The path is drawn in Fig. 12.3-1.

Diagram

Fig. 12.3-1 – flow: new SchoolBus(…) → SchoolBus constructor entered, first statement super(r,s) → Bus constructor entered, first statement super(r) → Vehicle constructor body runs to completion → control returns, Bus constructor body runs to completion → control returns, SchoolBus constructor body runs to completion → object ready. Draw the three downward steps as one column of arrows labelled “entering” and the three upward steps as a second column labelled “executing”

This order is not an accident of implementation; it is the only order that can work. The body of a derived class’s constructor is allowed to use inherited members, so those members must already hold sensible values by the time it starts. Building from the top of the hierarchy downwards guarantees exactly that.

The program below makes the order visible by printing a line from each constructor.

tracing the order of constructor execution in a three-level hierarchy Problem: Declare a class Vehicle holding a registration code, a class Bus derived from it holding the number of seats, and a class SchoolBus derived from Bus holding the route. Each class is to have a parameterised constructor that initialises only its own member and announces that it has run. Create one SchoolBus object and display all three details. The values are fixed inside main(); no input is read.

// Purpose: to show a subclass constructor passing values up the chain with
// super(...), and to make the order in which the constructors run visible.

class Vehicle
{
    protected String regNo;

    Vehicle(String r)
    {
        regNo = r;
        System.out.println("Vehicle part ready");
    }
}

class Bus extends Vehicle
{
    protected int seats;

    Bus(String r, int s)
    {
        super(r);
        seats = s;
        System.out.println("Bus part ready");
    }
}

class SchoolBus extends Bus
{
    private String route;

    SchoolBus(String r, int s, String rt)
    {
        super(r, s);
        route = rt;
        System.out.println("SchoolBus part ready");
    }

    void show()
    {
        System.out.println("Registration: " + regNo);
        System.out.println("Seats: " + seats);
        System.out.println("Route: " + route);
    }
}

class BusDemo
{
    public static void main(String args[])
    {
        SchoolBus sb = new SchoolBus("BUS-07", 42, "School Gate to Sector 5");
        sb.show();
    }
}

Sample output:

Vehicle part ready
Bus part ready
SchoolBus part ready
Registration: BUS-07
Seats: 42
Route: School Gate to Sector 5

Variable description:

[Table:] Table 12.5 – variables of the school bus program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | regNo | String | stores the registration code of the vehicle, declared in Vehicle | | seats | int | stores the number of seats, added by Bus | | route | String | stores the route travelled, added by SchoolBus | | r, s, rt | String, int, String | formal arguments carrying the registration code, seat count and route up the chain | | sb | SchoolBus | object whose creation sets off the chain of constructors |

Notes: the three constructors take progressively longer argument lists, because each one must accept the values needed by every class above it as well as its own. That is the usual shape of a constructor chain, and it is also its usual limitation: adding one variable to Vehicle obliges every constructor beneath it to grow by one argument.

creating one SchoolBus object with the arguments “BUS-07”, 42 and “School Gate to Sector 5”

Step What is executing regNo seats route Printed
1 SchoolBus(...) entered; first statement is super(r, s), so control leaves at once null 0 null —
2 Bus(...) entered; first statement is super(r), so control leaves at once null 0 null —
3 Vehicle(...) body runs completely “BUS-07” 0 null Vehicle part ready
4 control returns to Bus(...); its remaining statements run “BUS-07” 42 null Bus part ready
5 control returns to SchoolBus(...); its remaining statements run “BUS-07” 42 “School Gate to Sector 5” SchoolBus part ready
6 sb.show() runs on the finished object “BUS-07” 42 “School Gate to Sector 5” Registration: BUS-07 / Seats: 42 / Route: School Gate to Sector 5

Result: the output begins with Vehicle part ready, although Vehicle’s constructor was the last to be asked for and the first to finish. The trace shows why — every constructor in the chain is entered before any constructor body completes, and the object is built from the top of the hierarchy downwards.

Q. In step 1 the values of seats and route are shown as 0 and null. Where did those come from?

A. From Java itself. Instance variables are given their default values — 0 for numeric types, false for boolean, null for object references — as soon as the object’s memory is allocated, before any constructor body runs. A constructor does not create the variables; it replaces the values they already hold.

Add a second constructor to SchoolBus that takes only a registration code and a seat count, and sets the route to “not allotted”. Decide for yourself what its first statement must be. Then create one object with each constructor and confirm from the output that both build a complete object.

12.4 Redefinition of Variables and Methods in Subclasses

A derived class is not obliged to accept everything its superclass says. Along with adding new members, it may declare a member with a name already used above it — and this is called redefinition.

Java treats the two cases very differently, and the difference is the single most important idea in this section. When a variable is redefined, the subclass’s declaration merely covers the superclass’s, and both exist. When a method is redefined, the subclass’s version genuinely takes over. One of these is a trap and the other is the mechanism on which the rest of the chapter is built.

12.4.1 Redefining an Instance Variable

Suppose a superclass Period records that a school period runs for forty minutes, and a class LabPeriod derived from it wants that figure to be eighty. The obvious move is to declare minutes again inside LabPeriod.

What then happens is that the object holds two variables named minutes, one described by each class, as shown in Fig. 12.4-1. This is called variable hiding: inside the code of LabPeriod the name minutes refers to LabPeriod’s own variable and the inherited one is hidden, while super.minutes reaches past the hiding to the superclass’s variable.

Diagram

Fig. 12.4-1 – one rounded box labelled “one LabPeriod object” divided into two compartments, the upper labelled “declared in Period: minutes = 40” and the lower labelled “declared in LabPeriod: minutes = 80”. To the right, two labelled arrows: one from a box “code written inside LabPeriod” pointing to the lower compartment for the plain name minutes and, as a second dashed arrow, to the upper compartment for super.minutes; another from a box “code written inside Period” pointing only to the upper compartment

The last arrow in that figure is the one that catches people out. Code written inside Period was compiled knowing only Period’s variables, so it goes on using the forty even when it is running on a LabPeriod object. The program below shows exactly this happening.

showing that a redefined instance variable hides rather than replaces Problem: Declare a class Period holding the length of a school period in minutes, with a method that displays it. Derive a class LabPeriod that declares a variable of the same name with a different value, and display both values as well as the result of calling the superclass’s display method. No input is read.

// Purpose: to show that redefining an instance variable in a subclass hides
// the inherited one instead of replacing it, so that both continue to exist.

class Period
{
    protected int minutes = 40;

    void showLength()
    {
        System.out.println("Length in minutes: " + minutes);
    }
}

class LabPeriod extends Period
{
    protected int minutes = 80;

    void showBoth()
    {
        System.out.println("This class sees: " + minutes);
        System.out.println("The superclass value: " + super.minutes);
    }
}

class PeriodDemo
{
    public static void main(String args[])
    {
        LabPeriod lp = new LabPeriod();
        lp.showBoth();
        lp.showLength();
    }
}

Sample output:

This class sees: 80
The superclass value: 40
Length in minutes: 40

Variable description:

[Table:] Table 12.6 – variables of the period program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | minutes (in Period) | int | stores the length of an ordinary period; the hidden variable | | minutes (in LabPeriod) | int | stores the length of a laboratory period; the hiding variable | | lp | LabPeriod | object holding both variables, through which each is displayed |

Notes: read the third line of the output again. showLength() was called on a LabPeriod object and still printed 40, because that method’s body was written inside Period and the name minutes there was settled, once and for all, when Period was compiled. The object now reports two different lengths depending on which class’s code you ask.

That is why variable hiding is almost always a mistake rather than a technique. If a subclass needs a different value, the honest ways are to assign the inherited variable a new value in the subclass’s constructor, or to expose the value through a method that the subclass can override. Both leave one variable in the object, holding one truth.

Q. Does hiding also apply to a private variable of the superclass?

A. A subclass may reuse the name freely, since a private variable is not accessible in the subclass at all. But nothing is hidden in the ordinary sense, because there was never anything the subclass could see. The two variables simply coexist, and only Period’s own methods can reach Period’s copy.

12.4.2 Method Overriding

Methods behave in the opposite way, and the difference is deliberate. Declaring a method again in a derived class is called method overriding, and for objects of that class it genuinely takes the inherited version’s place.

NoteDefinition

Method overriding is the declaration, in a derived class, of a method having the same name, the same parameter list and the same return type as a method of its superclass, so that the derived class’s version is the one carried out for objects of the derived class.

The phrase “same name and same parameter list” is worth a name of its own. The signature of a method is its name together with the number, types and order of its parameters. Overriding requires the two signatures to match exactly; return types must match too, though from Java 5.0 onwards the overriding method may return a subclass of the type the superclass method returned.

Suppose a class Bill prints the details of a purchase at a school shop, and a class DiscountBill derived from it must print the same details and then a discount calculation. Declaring print() again in DiscountBill overrides it: for any DiscountBill object, print() now means the new version, and the superclass’s version is not carried out at all.

class DiscountBill extends Bill
{
    void print()
    {
        System.out.println("Item: " + item);
        System.out.println("Unit price: " + price);
        System.out.println("Quantity: " + qty);
        System.out.println("Amount payable: " + price * qty);
    }
}

Overriding is a genuine replacement, and that is exactly what makes this version unsatisfying: the first three lines have been copied out of the superclass, which is the duplication Section 12.1 set out to abolish. The repair is the subject of the next subsection.

Two rules limit what may be overridden. A private method cannot be overridden, because it is not visible in the subclass; a method with the same name declared there is simply a new and unrelated method. And an overriding method may not be less accessible than the one it overrides — a public method cannot be overridden by a protected one — because a subclass object must be usable everywhere a superclass object is usable.

changing the parameter list and expecting the method to override What students write:

class Bill
{
    void print()
    {
        System.out.println("Bill printed");
    }
}

class DiscountBill extends Bill
{
    void print(double rate)
    {
        System.out.println("Discounted bill printed");
    }
}

What happens: the program compiles and runs, and print() called on a DiscountBill object prints Bill printed. Nothing was overridden. The signatures differ, so DiscountBill now simply has two methods named print — the inherited one and a new one of its own — and the call with no argument matches the inherited one.

The fix: make the signatures identical, and pass the extra value another way — through the constructor, or as an instance variable of the subclass.

    void print()
    {
        System.out.println("Discounted bill printed");
    }

The silent nature of this error is what makes it dangerous. Overriding that fails announces nothing; the program merely goes on doing the old thing.

12.4.3 Invoking the Overridden Method with super

An overriding method usually does not want to abolish the superclass’s version. It wants to do that work and then a little more. For this, super appears in its second form:

super.methodName(actual arguments);

Used this way, super is not a constructor call and need not stand first; it is an ordinary call, and it means “run the version of this method that my superclass declared, on this same object”. Without it, writing print() inside DiscountBill.print() would call DiscountBill.print() again — the method calling itself endlessly.

Diagram

Fig. 12.4-2 – two boxes, an upper labelled “class Bill” containing “void print()” and a lower labelled “class DiscountBill extends Bill” containing “void print()”. A thick arrow from the lower box to the upper labelled “super.print() — run the inherited version”; beside it a plain label on the lower box reading “print() on a DiscountBill object means this one”

printing a school shop bill, with a derived class extending the superclass’s printing Problem: A superclass stores the name of an item, its unit price and the quantity bought, and prints these three details. A class derived from it also holds a discount rate as a percentage, and its printing must show the superclass’s three details followed by the amount before discount, the rate, and the amount payable. The values are fixed inside main(); no input is read.

// Purpose: to show a derived class overriding a method and using super to run
// the superclass's version of that same method before adding its own work.

class Bill
{
    protected String item;
    protected double price;
    protected int qty;

    Bill(String i, double p, int q)
    {
        item = i;
        price = p;
        qty = q;
    }

    void print()
    {
        System.out.println("Item: " + item);
        System.out.println("Unit price: " + price);
        System.out.println("Quantity: " + qty);
    }
}

class DiscountBill extends Bill
{
    private double rate;

    DiscountBill(String i, double p, int q, double r)
    {
        super(i, p, q);
        rate = r;
    }

    void print()
    {
        super.print();
        double gross = price * qty;
        double net = gross - gross * rate / 100.0;
        System.out.println("Amount before discount: " + gross);
        System.out.println("Discount rate: " + rate);
        System.out.println("Amount payable: " + net);
    }
}

class BillDemo
{
    public static void main(String args[])
    {
        DiscountBill d = new DiscountBill("Notebook", 25.0, 4, 10.0);
        d.print();
    }
}

Sample output:

Item: Notebook
Unit price: 25.0
Quantity: 4
Amount before discount: 100.0
Discount rate: 10.0
Amount payable: 90.0

Variable description:

[Table:] Table 12.7 – variables of the school shop bill program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | item | String | stores the name of the item bought | | price | double | stores the unit price of the item | | qty | int | stores the quantity bought | | rate | double | stores the discount as a percentage, added by DiscountBill | | gross | double | local variable holding the amount before discount | | net | double | local variable holding the amount payable after discount | | i, p, q, r | String, double, int, double | formal arguments carrying the item, price, quantity and discount rate | | d | DiscountBill | object whose print() produces the whole bill |

Notes: the first line of the overriding method does all the inherited work, so the three details are printed by the class that owns them. Should the shop later decide to print a serial number with every item, that change is made once, in Bill, and this bill gains it without being touched. Note also that gross and net are declared inside the method rather than as instance variables, because they are working values of one printing and are of no interest to the object afterwards.

Q. Can super.print() be written anywhere other than the first line?

A. Yes. Unlike super(...) in a constructor, super.print() is an ordinary statement and may appear wherever the logic needs it — last, if the added lines belong above the inherited ones, or not at all if the superclass’s version really is to be discarded.

12.4.4 Overloading Compared with Overriding

You met method overloading in Class XI: two or more methods in a class carrying the same name but different parameter lists, so that the compiler tells them apart by the arguments written at the call. Overriding also involves two methods of the same name, and the two ideas are confused so often that they are best set side by side.

Table 12.8 – method overloading compared with method overriding

Feature Method overloading Method overriding
Where the two methods are usually in one class; a subclass method may also overload an inherited one one in the superclass, the other in the derived class
Parameter lists must differ in number, type or order must be identical
Return type may be the same or different the same, or a subclass of it
Inheritance not needed essential
Which method runs is decided at compile time, from the arguments written at the call at run time, from the class of the object the call is made on
Purpose to offer one operation in several convenient forms to give a specialised class its own version of an inherited operation
Commonly called compile-time polymorphism run-time polymorphism

The fifth row is the real distinction, and everything else follows from it. In overloading, the compiler can see the arguments and settle the matter there and then. In overriding, the arguments are identical in both versions, so the arguments cannot decide anything; the only thing that differs is which kind of object the method is being carried out on, and that is not always known until the program runs.

The last row of the table uses a word this chapter has not yet defined. Polymorphism is one name standing for more than one behaviour; overloading and overriding are its two forms, and the second — the form that only inheritance makes possible — is the doorway to Section 12.6.

Take the bill program and add to DiscountBill a second method print(String heading) that prints the heading and then calls print(). Before compiling, write down whether this new method overloads print(), overrides it, or neither. Then compile, call both forms on one object, and check your answer against the output.

12.5 The Class Object

Every class written so far in this chapter has fallen into one of two groups: those that name a superclass with extends, and those that do not. That division turns out to be less real than it looks. In Java there is no class of the second kind — only classes whose superclass is not written down.

12.5.1 The Root of Every Class Hierarchy

Java supplies a class named Object, which belongs to the package java.lang and is therefore available in every program without an import statement. It occupies a position no other class does.

NoteDefinition

Object is the class from which every other class in Java is descended. A class that declares no superclass has Object as its immediate superclass, and a class that declares one is descended from Object through it.

So Vehicle, in Section 12.3, extends Object although its declaration says nothing of the kind, and SchoolBus is descended from Object at three removes. Draw all the classes of a Java program together and you do not get a scatter of separate hierarchies; you get one tree, with Object at its root, as in Fig. 12.5-1.

Diagram

Fig. 12.5-1 – a box labelled “Object” at the top, drawn wider than the rest. Below it, joined by dashed upward arrows labelled “extends Object, written by no one”, three boxes: Vehicle, Bill and Distance. Below Vehicle a solid arrow up from Bus, and below Bus a solid arrow up from SchoolBus; below Bill a solid arrow up from DiscountBill. The solid arrows are labelled “extends, written by the programmer”

Two consequences follow, and both matter.

The first is that every object in Java, of every class, already possesses a small set of methods before its own class declares anything. They are inherited from Object in the ordinary way described in Section 12.1, and a few of them are used constantly.

Table 12.9 – methods inherited from Object by every class, and what each does if it is not overridden

Method What it gives back Behaviour if not overridden
toString() a String describing the object the name of the object’s class, an @, and a code in hexadecimal
equals(Object o) boolean true only when o refers to the very same object
hashCode() int a code derived from the object, different objects normally giving different codes
getClass() an object describing the class reports the class the object actually belongs to, whatever the reference’s type

The default toString() is worth seeing once. Printing an object of a class that has not overridden it produces something of the form Distance@1b6d3586, in which the part after the @ differs from one run to the next. It tells you the class and nothing else, which is rarely what you wanted — and that is the whole motivation for the next subsection.

The second consequence is about types. Because every class is descended from Object, a variable declared of type Object may refer to an object of any class whatever. That single fact is what lets Java’s library be written once and used with classes that did not exist when it was written. It is also the first hint of the idea developed in Section 12.6.

Q. If Object is the superclass of everything, why does a class not have to write extends Object?

A. Because the compiler inserts it. Writing it changes nothing and is simply unusual. Object itself is the one exception in the language: it has no superclass, which is what makes it the root.

12.5.2 Redefining toString() and equals()

The methods in Table 12.9 are inherited, so they may be overridden exactly as any other inherited method is. Nothing new is needed: the rules of Section 12.4.2 apply unchanged, including the rule that an overriding method may not be less accessible than the one it overrides. Since Object declares these methods public, your versions must be declared public too.

Overriding toString() is the more useful of the two and the easier to justify. Java calls it automatically wherever an object is used in a place that requires a String — when an object is joined to a string with +, and when an object is passed to System.out.println(). Give a class a sensible toString() and its objects become printable in one line, everywhere, for ever.

Overriding equals() answers a different question: when should two distinct objects count as the same? The inherited version says “never, unless they are literally one object”. For a class such as Distance, where two separately created objects may well record the same length, that answer is unhelpful, and the class must supply its own.

giving a class its own toString() and equals() Problem: Declare a class Distance that stores a length as a whole number of kilometres and metres. Its toString() is to describe the distance in the form 12 km 500 m, and its equals() is to report two distances as equal when they represent the same number of metres. Create two separately built objects of the same length and display them, along with the results of comparing them with == and with equals(). No input is read.

// Purpose: to override the toString() and equals() methods inherited from
// Object, so that objects of this class print sensibly and compare by value.

class Distance
{
    private int km;
    private int metres;

    Distance(int k, int m)
    {
        km = k;
        metres = m;
    }

    int totalMetres()
    {
        return km * 1000 + metres;
    }

    public String toString()
    {
        return km + " km " + metres + " m";
    }

    public boolean equals(Object o)
    {
        if (o instanceof Distance)
        {
            Distance d = (Distance) o;
            return totalMetres() == d.totalMetres();
        }
        return false;
    }
}

class DistanceDemo
{
    public static void main(String args[])
    {
        Distance a = new Distance(12, 500);
        Distance b = new Distance(12, 500);
        System.out.println("First: " + a);
        System.out.println("Second: " + b);
        System.out.println("a == b gives " + (a == b));
        System.out.println("a.equals(b) gives " + a.equals(b));
    }
}

Sample output:

First: 12 km 500 m
Second: 12 km 500 m
a == b gives false
a.equals(b) gives true

Variable description:

[Table:] Table 12.10 – variables of the distance program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | km | int | stores the whole kilometres of the distance | | metres | int | stores the metres left over | | k, m | int, int | formal arguments of the constructor receiving the two parts | | o | Object | formal argument of equals(), able to receive an object of any class | | d | Distance | local reference used to reach the other object’s totalMetres() | | a, b | Distance | two separately created objects recording the same length |

Notes: two pieces of Java in equals() are new. The operator instanceof yields true when the object referred to on its left belongs to the class named on its right, so the test asks whether the argument is a Distance at all; anything else cannot be equal to a distance, and the method reports false. The bracketed class name in (Distance) o is a cast: it tells the compiler to treat that reference as a Distance reference, which is safe here precisely because the test has just succeeded. Note also that the parameter must be declared Object and not Distance. Declaring it Distance would produce a method with a different signature, which — by the rule of Section 12.4.2 — would not override anything at all, and the inherited equals() would go on being used.

The two comparison lines of the output are the point of the program, and they deserve a table of their own.

Table 12.11 – == compared with equals() when applied to objects

Feature == equals()
What it is an operator built into the language a method inherited from Object
What it compares, for objects the two references — whether they lead to one and the same object whatever the class decides, if the class overrides it
Can the programmer change its meaning no yes, by overriding it
Behaviour if equals() is not overridden compares references compares references, giving the same result as ==
Result for a and b above false, because two objects were created true, because both record 12500 metres

For primitive types such as int and char, == compares values in the ordinary way and no confusion arises. The trouble begins the moment == is used between two object references — including two String references — where it asks a question about identity, not about content.

One convention should be mentioned honestly. Java’s own library classes assume that two objects reported equal by equals() return the same value from hashCode(). A class that overrides equals() and leaves hashCode() alone will behave correctly in a program such as the one above, but may behave oddly if its objects are later stored in a library structure that groups items by hash code. The safe habit is to override the two together.

Remove the toString() method from Distance, recompile and run the program. Note the form of the first two lines of output, and note that the fourth line is unchanged. Then restore toString(), remove equals() instead, and predict the last line before you run it.

12.6 Subclass Polymorphism and Dynamic Binding

Section 12.4 defined polymorphism as one name standing for more than one behaviour, and named its two forms. The compile-time form was already familiar from Class XI. This section takes the other one — the form that only inheritance can produce — and it is the point towards which the whole chapter has been building.

Two facts make it work, and neither is obvious. The first is that a reference variable declared of a superclass type is allowed to refer to an object of any class derived from it. The second is that when an overridden method is called through such a reference, the version that runs belongs to the object, not to the reference. Take these in turn.

12.6.1 One Superclass Reference, Many Subclass Objects

A reference variable has a declared type; an object has a class. Until now the two have always matched. They need not.

Parcel p = new SpeedParcel("P102", 2.0);

This is legal Java, provided SpeedParcel is derived from Parcel. The compiler permits it for the reason given in Section 12.1.5: a SpeedParcel is a Parcel, so a variable that promises to refer to a parcel has not been made to break its promise. The conversion from the subclass type to the superclass type happens automatically, with nothing written, and the ability this gives has a name: subclass polymorphism.

NoteDefinition

Subclass polymorphism is the ability of a reference variable of a superclass type to refer to an object of any class derived from that superclass, so that one variable, one array element or one method argument can handle objects of several related classes.

The reverse assignment is not allowed. SpeedParcel s = new Parcel(...); is rejected, and rightly: an ordinary parcel is not a speed parcel and would be missing whatever a speed parcel adds.

There is a price, and it is easy to forget. The compiler checks every call against the declared type of the reference, not against the object it happens to hold. Through a Parcel reference you may use only the members Parcel declares — even when the object at the other end is a SpeedParcel with members of its own. Fig. 12.6-1 draws this as a window: the object is whole, but the reference lets you see only part of it.

Diagram

Fig. 12.6-1 – on the left a small box labelled “Parcel p” with an arrow running right to a large rounded box labelled “a SpeedParcel object”. The large box has two compartments, the upper labelled “Parcel part: docket, weight, charge(), printCharge()” and the lower labelled “SpeedParcel part: tracking()”. A narrow rectangular frame labelled “what the reference p allows” is drawn over the upper compartment only, with the lower compartment outside it and marked “present in the object, but not reachable through p”

calling a subclass method through a superclass reference What students write:

class Parcel
{
    double charge()
    {
        return 40.0;
    }
}

class SpeedParcel extends Parcel
{
    String tracking()
    {
        return "SP-0001";
    }
}

class Test
{
    public static void main(String args[])
    {
        Parcel p = new SpeedParcel();
        System.out.println(p.tracking());
    }
}

What happens: the program does not compile. The compiler reports that it cannot find a method tracking() in class Parcel. The object certainly has one, but the compiler is judging by the declared type of p, and Parcel promises no such method.

The fix: declare the reference as SpeedParcel if that is what it will always hold. If it cannot be — because the reference must also hold ordinary parcels — then test the object and convert before calling.

        if (p instanceof SpeedParcel)
        {
            SpeedParcel sp = (SpeedParcel) p;
            System.out.println(sp.tracking());
        }

The cast is safe only because instanceof has just confirmed what the object is; a cast written without that check compiles happily and fails while the program is running.

12.6.2 Dynamic Binding: Choosing the Method at Run Time

Now the second fact, and it points the opposite way from the first. The compiler decides whether a call is allowed from the reference’s declared type. Java decides which version to carry out from the object’s actual class — and it does so while the program is running. That second mechanism is called dynamic binding.

NoteDefinition

Dynamic binding is the mechanism by which the version of an overridden method to be carried out is chosen while the program is running, from the class of the object on which the method is called, rather than from the declared type of the reference used to call it. It is also called late binding or run-time binding.

Its opposite is static binding, also called early binding, in which the compiler settles the matter and nothing can change it afterwards. Static binding governs instance variables, and it is exactly why the redefined variable in Section 12.4.1 behaved as it did: the name minutes in a method of Period was bound to Period’s variable when Period was compiled, whatever object the method later ran on. Methods behave the other way, and the following program shows it.

charging three kinds of parcel through one superclass reference Problem: A superclass stores a parcel’s docket number and its weight and charges rupees 40 per kilogram. A speed parcel is charged twice the ordinary rate and a local parcel half of it. Store one parcel of each kind in a single array of the superclass type and print the charge for each. The values are fixed inside main(); no input is read.

// Purpose: to show one superclass reference holding objects of several
// subclasses, with the overridden method chosen by the object at run time.

class Parcel
{
    protected String docket;
    protected double weight;

    Parcel(String d, double w)
    {
        docket = d;
        weight = w;
    }

    double charge()
    {
        return weight * 40.0;
    }

    void printCharge()
    {
        System.out.println(docket + " : " + charge());
    }
}

class SpeedParcel extends Parcel
{
    SpeedParcel(String d, double w)
    {
        super(d, w);
    }

    double charge()
    {
        return super.charge() * 2;
    }
}

class LocalParcel extends Parcel
{
    LocalParcel(String d, double w)
    {
        super(d, w);
    }

    double charge()
    {
        return super.charge() / 2;
    }
}

class ParcelDemo
{
    public static void main(String args[])
    {
        Parcel list[] = new Parcel[3];
        list[0] = new Parcel("P101", 2.0);
        list[1] = new SpeedParcel("P102", 2.0);
        list[2] = new LocalParcel("P103", 2.0);

        for (int i = 0; i < list.length; i++)
        {
            list[i].printCharge();
        }
    }
}

Sample output:

P101 : 80.0
P102 : 160.0
P103 : 40.0

Variable description:

[Table:] Table 12.12 – variables of the parcel program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | docket | String | stores the docket number written on the parcel | | weight | double | stores the weight of the parcel in kilograms | | d, w | String, double | formal arguments of the constructors receiving the docket and weight | | list | Parcel[] | array of superclass references holding one object of each kind | | i | int | loop variable stepping through the array |

Notes: three things in this listing deserve a second look. The array is declared Parcel[], yet two of its three elements refer to objects of other classes — that is subclass polymorphism. The loop body contains one call, written once, which produced three different amounts — that is dynamic binding. And printCharge() was declared only in Parcel and never overridden, yet it printed the specialised charges; the call to charge() inside it is bound at run time exactly like any other, even though the code around it was written in the superclass and compiled long before SpeedParcel existed.

the loop of ParcelDemo, on the three objects created in main()

i Class of the object in list[i] Version of charge() carried out Value it returns Line printed
0 Parcel Parcel.charge() 2.0 × 40.0 = 80.0 P101 : 80.0
1 SpeedParcel SpeedParcel.charge(), which calls Parcel.charge() through super 80.0 × 2 = 160.0 P102 : 160.0
2 LocalParcel LocalParcel.charge(), which calls Parcel.charge() through super 80.0 ÷ 2 = 40.0 P103 : 40.0

Result: the three lines of the output above. The trace shows that the column which changes is the second one — the class of the object — and that everything else about the call is identical each time round the loop.

Q3. Two objects are handled by exactly the same line of code, yet they print different things. How does the program decide what to do?

A. By the class of the object, not by the code around the call. A superclass reference may refer to an object of any of its subclasses, and when an overridden method is called through it, Java looks at the object actually present and carries out that class’s version of the method. This choice is made while the program is running, which is why it is called dynamic binding, and it is why one line inside a loop produced three different charges.

Table 12.13 – static binding compared with dynamic binding

Feature Static binding Dynamic binding
When the choice is made at compile time while the program is running
What settles the choice the declared type of the reference the class of the object referred to
Applies to instance variables and overloaded methods overridden methods
Also called early binding late binding, run-time binding
Effect of using a superclass reference the superclass’s variable is used the subclass’s method is used
Can it be predicted by reading one class alone yes not always; it depends on the object supplied

The fifth row is the one worth memorising, because it is the sentence that resolves almost every question of this kind: through a superclass reference, variables come from the reference and methods come from the object.

12.6.3 What Polymorphism Buys the Programmer

It is fair to ask what all this is for, since the parcel program could have been written with three separate arrays and no inheritance at all.

The answer is what happens next. Suppose the courier now offers a fourth kind of parcel, charged at one and a half times the ordinary rate. You write one new class extending Parcel and overriding charge(). Nothing else changes: not printCharge(), not the array, not the loop, not one line of main() beyond the object being created. Code that was written and tested before the new class existed goes on working with it. A program built this way is open to new kinds without being reopened for repair, and that — far more than the saving of a few duplicated lines — is why inheritance is worth the trouble.

The second gain is uniform treatment. A group of related objects can be held in one array, passed to one method and processed by one loop, precisely because the superclass guarantees that every one of them answers to charge(). The superclass has become a promise about behaviour rather than merely a store of common data.

Three honest limitations belong beside those gains.

First, the superclass reference narrows what you can reach. Anything a subclass adds is invisible through it, and getting at it needs an instanceof test and a cast — which, if it starts appearing all over a program, is usually a sign that the operation should have been declared in the superclass and overridden instead.

Second, reading the program becomes harder, not easier. list[i].printCharge() tells you nothing about what will be printed. To know, you must find which class the object belongs to, and that may have been decided far away.

Third, the superclass must be designed for it. charge() had to exist in Parcel for any of this to work. If a superclass is written without thought for what its subclasses will need to redefine, its subclasses cannot use polymorphism however hard they try — and that is the difficulty which leads directly to the abstract classes of Section 12.7.

Add a class HeavyParcel that extends Parcel and charges one and a half times the ordinary rate, and put one such object into the array by enlarging it to four elements. Count how many existing lines of the program you had to alter to make the new charge appear in the output.

12.7 Abstract Classes

Section 12.6 ended on a difficulty. Polymorphism works only if the superclass declares the operation that the subclasses redefine — and sometimes the superclass has nothing sensible to put in it.

Parcel was fortunate: an ordinary parcel really does have a charge, and the superclass could compute it. Now think of a class Shape, with Rectangle and Triangle derived from it. Every shape has an area, so area() certainly belongs in Shape. But what would its body contain? There is no formula for the area of a shape in general; there are only formulas for particular shapes. And what would an object of Shape itself represent — a shape that is no shape in particular?

Java’s answer to both questions is the abstract class.

12.7.1 A Class That Should Never Be Instantiated

A class declared with the keyword abstract — an abstract class — may be inherited, but no object of it may be created.

NoteDefinition

An abstract class is a class declared with the keyword abstract, of which no object can be created. It exists to be extended: it holds the members common to its subclasses and fixes what they must all be able to do.

abstract class Shape
{
    protected String name;

    Shape(String n)
    {
        name = n;
    }
}

Writing new Shape("something") anywhere in the program is now a compile-time error, and that is the whole of the restriction. Everything else about the class is unchanged. An abstract class may have instance variables, ordinary methods with bodies, and — as above — constructors. Its constructor is not wasted: a subclass calls it with super(...), exactly as in Section 12.3, and it initialises the inherited part of the subclass’s object.

A class that is not abstract is called a concrete class. Rectangle and Triangle will be concrete; objects of them can be created in the usual way.

One consequence is easy to state and easy to misread. You may not create a Shape object, but you may declare a Shape reference:

Shape s;

That is not a contradiction. A reference variable holds no object; it merely says what kind of object it is allowed to refer to. Assigning s = new Rectangle(8.0, 5.0); is perfectly legal, since a rectangle is a shape. So an abstract class can still serve as the common type of Section 12.6.1 — indeed that is one of the two things it is for. The other is the subject of the next subsection.

Q. Must an abstract class contain something unusual to deserve the keyword?

A. No. Declaring a class abstract forbids the creation of its objects and does nothing else; a class with every method fully written may still be declared abstract if objects of it would be meaningless. In practice, though, most abstract classes are abstract because of what the next subsection describes.

12.7.2 Abstract Methods

The second thing an abstract class can do is declare a method without writing it. Such a declaration is an abstract method.

NoteDefinition

An abstract method is a member method declared with the keyword abstract and with no body at all, its declaration ending in a semicolon. It states the method’s name, return type and arguments, and leaves every subclass to supply the statements.

    abstract double area();

Note the semicolon where a body would be. Three rules follow from this declaration, and the compiler enforces all three.

  1. A class containing even one abstract method must itself be declared abstract. A class cannot promise a method it does not have and still allow objects to be made.
  2. Every concrete subclass must override every abstract method it inherits. Failing to do so is a compile-time error, not a silent gap.
  3. A subclass that overrides only some of them must itself be declared abstract, and passes the remaining obligation down to its subclasses.

Rule 2 is the reason abstract methods exist. In Section 12.6 the superclass could only hope that its subclasses would override charge(); if one forgot, the inherited version ran and the mistake went unnoticed. An abstract method converts that hope into a requirement checked by the compiler before the program will even run. The whole arrangement is drawn in Fig. 12.7-1.

Diagram

Fig. 12.7-1 – an upper box labelled “abstract class Shape”, drawn with a dashed outline, listing the variable name, the constructor Shape(String), the entry “abstract double area();” marked “declared, no body” and the method show() marked “written in full”. Beside it, the text “new Shape()” crossed out and labelled “no object of this class”. Below, two solid boxes “class Rectangle” and “class Triangle”, each listing its own dimensions and its own double area() marked “body supplied here”, joined to the Shape box by upward arrows labelled “extends”. A dashed arrow from show() curving down to both area() bodies, labelled “chosen at run time”

writing an empty body instead of no body What students write:

    abstract double area()
    {
    }

What happens: the compiler rejects the declaration. A method declared abstract may not have a body, and a pair of braces — even with nothing between them — is a body. (Left alone without the keyword, double area() { } fails too, for a different reason: a method with a return type must return something.)

The fix: end the declaration with a semicolon and write no braces.

    abstract double area();

The distinction between “no body” and “an empty body” is not a quibble, because a method with an empty body is an ordinary method that happens to do nothing — it can be inherited, called, and quietly left unoverridden for ever.

Table 12.14 – an abstract method compared with a method having an empty body

Feature Abstract method Method with an empty body
How it is written abstract keyword, no braces, ends with a semicolon no abstract keyword, a pair of empty braces
Return type allowed any, since the subclass supplies the return only void, since nothing is returned
Effect on its class the class must be declared abstract none; the class may stay concrete
Is a subclass obliged to override it yes, if the subclass is concrete no
What happens when it is called the subclass’s version runs; this class has none nothing at all happens
What it communicates every subclass must decide this for itself this operation exists but has nothing to do here

Now the two ideas can be put together in one program.

finding the area of a rectangle and of a triangle through an abstract superclass Problem: Declare an abstract class Shape that stores the name of a shape, declares an abstract method to find its area, and has a concrete method that displays the name along with the area. Derive a class Rectangle holding a length and a breadth, and a class Triangle holding a base and a height, each supplying its own area. Display one shape of each kind. The values are fixed inside main(); no input is read.

// Purpose: to show an abstract class fixing an operation that every subclass
// must supply, and using it from a method written in the abstract class.

abstract class Shape
{
    protected String name;

    Shape(String n)
    {
        name = n;
    }

    abstract double area();

    void show()
    {
        System.out.println(name + " has area " + area());
    }
}

class Rectangle extends Shape
{
    private double length;
    private double breadth;

    Rectangle(double l, double b)
    {
        super("Rectangle");
        length = l;
        breadth = b;
    }

    double area()
    {
        return length * breadth;
    }
}

class Triangle extends Shape
{
    private double base;
    private double height;

    Triangle(double b, double h)
    {
        super("Triangle");
        base = b;
        height = h;
    }

    double area()
    {
        return 0.5 * base * height;
    }
}

class ShapeDemo
{
    public static void main(String args[])
    {
        Rectangle r = new Rectangle(8.0, 5.0);
        Triangle t = new Triangle(6.0, 4.0);
        r.show();
        t.show();
    }
}

Sample output:

Rectangle has area 40.0
Triangle has area 12.0

Variable description:

[Table:] Table 12.15 – variables of the shape program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | name | String | stores the name of the shape, declared in Shape | | length, breadth | double, double | dimensions of the rectangle | | base, height | double, double | dimensions of the triangle | | n | String | formal argument of the Shape constructor receiving the name | | l, b, h | double | formal arguments of the subclass constructors receiving the dimensions | | r, t | Rectangle, Triangle | the two objects displayed |

Notes: look at show(). It is written inside Shape, in a class that has no idea how any area is computed, and it calls area() regardless. This is dynamic binding again, but with a guarantee attached: in Section 12.6 the superclass merely hoped a subclass would override the method, whereas here the compiler will not allow a concrete subclass to exist without one. show() is therefore safe by construction, which is a stronger statement than any amount of careful programming can make.

Q4. What use is a class if you are forbidden to create even a single object of it?

A. Two uses, and neither needs an object of it. It gathers the members common to a family of classes into one place, so that its subclasses inherit them and its constructor initialises them. And it fixes what every member of that family must be able to do: an abstract method, having no body, obliges every concrete subclass to supply one, so a method written in the abstract class can call it with confidence. The class exists to be extended, and a reference of its type may still refer to any of its subclass objects.

12.7.3 A Class as an Abstract Data Type

Step back from the keyword and look at what Shape actually is. It says that a shape has a name and an area. It does not say how an area is obtained, and it holds no length, no breadth and no base. Anyone writing code against Shape can use the operation without knowing the representation — and different subclasses use entirely different representations to satisfy the same promise.

That arrangement has a name.

NoteDefinition

An abstract data type (ADT) is a type defined by the operations that may be performed on it and by what those operations do, and not by the way its data is stored or its operations are carried out.

The two Java features you have met make an abstract data type (ADT) possible. Encapsulation, from Section 12.2, keeps the representation private so that no user of the type can depend on it. Abstract methods fix the operations so that every implementation must provide them. What remains visible is a set of promises about behaviour, which is exactly what an ADT is.

This is worth recognising because it is how the data structures of your later work are described: a stack is not a particular arrangement of memory but a type on which you may push, pop and test for emptiness; a queue is a type you may add to at one end and remove from at the other. Two different classes may implement a stack in two different ways, and any program written against the operations will work with both.

An honest qualification closes the section. An abstract class makes a partial abstract data type, because along with the promises it also carries data members and written-out methods that every subclass is forced to inherit. Shape obliges each of its subclasses to have a name, whether that suits them or not. For an abstract data type in its pure form — operations and nothing else, imposed on classes that need share no data and no ancestry at all — Java offers a separate construct, and it is the subject of Section 12.8.

Add the line Shape s = new Shape("any shape"); to main(), compile, and read the message the compiler gives. Then replace it with Shape s = new Rectangle(3.0, 3.0); followed by s.show(); and compile again. Write one sentence explaining why the first line is rejected and the second is not, although both mention Shape on the left.

12.8 Interfaces in Java

Section 12.7 closed on a promise: that Java has a construct for stating what a class must be able to do, imposed on classes that share no data and no ancestry. That construct is the interface, and it settles the question left open all the way back in Section 12.1.4.

12.8.1 Why Java Needs Interfaces

Two difficulties have accumulated, and one construct answers both.

The first is multiple inheritance. Java forbids a class to extend two classes, because if both wrote a body for the same method there would be no honest way to decide which body an object should use. Note carefully where the ambiguity lies: in the bodies. If neither class supplied a body — if both merely stated that the method must exist — there would be nothing to clash. A class could take such a statement from any number of sources without contradiction.

The second is that classes belong to families, but behaviour does not. A Book is a library item and takes its place in that hierarchy. Yet the school also lends out a projector, which is no kind of library item at all, and both need to be charged rent. “Can be rented” is not a place in the hierarchy; it is a role, and it cuts across the tree, as Fig. 12.8-1 shows. An abstract class cannot express it, because a class may extend only one superclass and Projector has no business extending LibraryItem.

Diagram

Fig. 12.8-1 – on the left a small hierarchy: a box “LibraryItem” with two boxes “Book” and “Magazine” beneath it joined by upward arrows labelled “extends”. On the right, an unconnected box “Projector”. Across the whole figure a horizontal dashed band labelled “Rentable” passes through the Book box and the Projector box only, leaving LibraryItem and Magazine outside it. Caption line: “a role that is not a place in any hierarchy”

An interface answers both. It states operations and supplies no bodies, so nothing can clash and a class may take on as many interfaces as it needs. And it is independent of the inheritance tree, so entirely unrelated classes may share a role.

12.8.2 Defining an Interface

An interface is written much like a class, with the keyword interface in place of class.

interface interface_name
{
    constants
    method declarations without bodies
}
NoteDefinition

An interface is a named collection of constants and of method declarations that have no bodies. It cannot be used to create objects; it exists so that classes may declare that they provide the methods it names.

Here is one for the role of Fig. 12.8-1.

interface Rentable
{
    int MAX_DAYS = 14;

    double rentFor(int days);
}

Two things in those four lines are not what they appear to be, because the compiler supplies modifiers that you are not obliged to write.

Table 12.16 – what the compiler adds to the members of an interface

As written in the interface What it actually means Consequence
int MAX_DAYS = 14; public static final int MAX_DAYS = 14; it is a constant shared by everyone, and it must be given a value where it is declared
double rentFor(int days); public abstract double rentFor(int days); it has no body, and any class implementing it must supply one

Three rules follow, and they are worth stating plainly. An interface cannot have instance variables — a variable declared in it is a constant, the same for every object of every class that implements it, and it can never be assigned to afterwards. An interface cannot have constructors, since no object of it is ever created. And in the form used throughout this book, an interface declares no method bodies at all; later versions of Java relax this, but nothing here needs the relaxation.

An interface may, however, be extended by another interface, using extends exactly as a class does:

interface Trackable
{
    String assetCode();
}

interface Traceable extends Trackable
{
    String lastSeenAt();
}

A class implementing Traceable must now supply both methods. Note the keyword: one interface extends another; it does not implement it, because there is nothing to implement.

12.8.3 Implementing an Interface through a Class

A class announces that it provides an interface’s methods with the keyword implements:

class classname implements interface_name
{
    class body
}

The class must then define every method the interface declares, or else be declared abstract itself and pass the obligation to its own subclasses. This is exactly the rule for abstract methods in Section 12.7.2, and for the same reason.

One extra rule catches almost everybody once. Every method of an interface is public, and Section 12.4.2 forbids an overriding method to be less accessible than the method it overrides. The implementing methods must therefore be declared public, even though the interface did not say so.

charging rent for a projector lent out by a school Problem: Declare an interface Rentable holding the greatest number of days for which anything may be charged, and declaring a method that returns the rent for a given number of days. Write a class Projector that implements it, charging a fixed daily rate but never for more than the maximum number of days. Display the rent for ten days and for twenty days. The values are fixed inside main(); no input is read.

// Purpose: to show a class implementing an interface by supplying a body for
// the method the interface only declares.

interface Rentable
{
    int MAX_DAYS = 14;

    double rentFor(int days);
}

class Projector implements Rentable
{
    private String code;
    private double dailyRent;

    Projector(String c, double r)
    {
        code = c;
        dailyRent = r;
    }

    public double rentFor(int days)
    {
        if (days > MAX_DAYS)
        {
            days = MAX_DAYS;
        }
        return days * dailyRent;
    }

    void show(int days)
    {
        System.out.println("Item: " + code);
        System.out.println("Days kept: " + days);
        System.out.println("Rent: " + rentFor(days));
    }
}

class RentDemo
{
    public static void main(String args[])
    {
        Projector p = new Projector("PRJ-2", 150.0);
        p.show(10);
        p.show(20);
    }
}

Sample output:

Item: PRJ-2
Days kept: 10
Rent: 1500.0
Item: PRJ-2
Days kept: 20
Rent: 2100.0

Variable description:

[Table:] Table 12.17 – variables of the projector program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | MAX_DAYS | int | constant of the interface, the greatest number of days chargeable | | code | String | stores the identifying code of the projector | | dailyRent | double | stores the rent charged for one day | | c, r | String, double | formal arguments of the constructor receiving the code and daily rate | | days | int | formal argument holding the number of days, in both rentFor() and show() | | p | Projector | the object whose rent is displayed |

Notes: the second reading shows twenty days but a rent of only 2100.0, because rentFor() reduced its own copy of days to the maximum before multiplying — and the constant that fixed the maximum was declared not in the class but in the interface, where it is written once for every class that ever implements it. Note also that rentFor() is public while show() is not: only the interface method is compelled.

forgetting public on an implementing method What students write:

class Projector implements Rentable
{
    double rentFor(int days)
    {
        return days * 150.0;
    }
}

What happens: the class does not compile. The compiler reports that the method is attempting to assign weaker access privileges — the interface declared rentFor() public, and this version, with no specifier, is less accessible than that.

The fix: declare it public.

    public double rentFor(int days)

This is not a special rule about interfaces. It is the ordinary rule about overriding, applied to a method that was public without anyone writing the word.

12.8.4 Implementing More Than One Interface

A class may implement any number of interfaces, named after implements and separated by commas. It may do this while also extending a class — in which case extends is written first:

class classname extends superclass implements Interface1, Interface2

The class must then supply a body for every method of every interface it names. There is no ambiguity to resolve, because no interface brought a body with it. This arrangement is drawn in Fig. 12.8-2.

Diagram

Fig. 12.8-2 – a box “class Cycle” at the bottom centre. A solid upward arrow from it, labelled “extends”, to a box “class Equipment” above it. Two dashed upward arrows from the same box, labelled “implements”, going to two boxes drawn with dashed outlines on either side, “interface Rentable” and “interface Trackable”. A note beside the solid arrow reads “at most one”; a note beside the dashed arrows reads “as many as required”

a school cycle that extends a class and implements two interfaces Problem: Declare an interface Rentable as before and an interface Trackable that declares a method returning an asset code. Write a class Equipment holding the name of a piece of equipment, and a class Cycle that extends Equipment and implements both interfaces. Display the name, the asset code and the rent for three days, and then obtain the rent for two days through a reference of the interface type. The values are fixed inside main(); no input is read.

// Purpose: to show one class extending a class and implementing two
// interfaces, and an interface used as the type of a reference.

interface Rentable
{
    int MAX_DAYS = 14;

    double rentFor(int days);
}

interface Trackable
{
    String assetCode();
}

class Equipment
{
    protected String name;

    Equipment(String n)
    {
        name = n;
    }

    void describe()
    {
        System.out.println("Equipment: " + name);
    }
}

class Cycle extends Equipment implements Rentable, Trackable
{
    private int serial;

    Cycle(String n, int s)
    {
        super(n);
        serial = s;
    }

    public double rentFor(int days)
    {
        return days * 20.0;
    }

    public String assetCode()
    {
        return "CYC-" + serial;
    }
}

class CycleDemo
{
    public static void main(String args[])
    {
        Cycle c = new Cycle("School cycle", 7);
        c.describe();
        System.out.println("Asset code: " + c.assetCode());
        System.out.println("Rent for 3 days: " + c.rentFor(3));

        Rentable r = c;
        System.out.println("Rent for 2 days: " + r.rentFor(2));
    }
}

Sample output:

Equipment: School cycle
Asset code: CYC-7
Rent for 3 days: 60.0
Rent for 2 days: 40.0

Variable description:

[Table:] Table 12.18 – variables of the cycle program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | name | String | stores the name of the equipment, declared in Equipment | | serial | int | stores the serial number of the cycle | | n, s | String, int | formal arguments of the Cycle constructor | | days | int | formal argument holding the number of days rented | | c | Cycle | the object, reached through its own class type | | r | Rentable | interface reference referring to the same object |

Notes: the last two lines are the ones to study. r is declared of an interface type, holds the very same object as c, and can call rentFor() because that is what Rentable promises — but it could not call assetCode() or describe(), which Rentable says nothing about. This is the restriction of Section 12.6.1 again, now applied to an interface: the reference decides what may be called, the object decides what runs. The gain is that a method taking a Rentable argument would accept a Cycle, a Projector, or any class implementing the interface, whatever their ancestry.

Q5. Java refuses to let a class extend two classes at once. So how can one class take on behaviour described in two different places?

A. By implementing two interfaces. The refusal exists because two superclasses could supply two conflicting bodies for the same method, and Java would have no honest way to choose between them. An interface supplies no bodies at all — only the names, arguments and return types of methods the class undertakes to write itself — so there is nothing to conflict. A class may therefore extend at most one class but implement as many interfaces as it needs, and it must supply a body for every method every one of them declares.

12.8.5 Interfaces for User Defined Implementation of Behaviour

So far an interface has described what a class is able to do. It has a second and more powerful use: letting the writer of one class leave a decision to whoever uses it.

Consider a class that sorts an array. The sorting itself — comparing two items and exchanging them — is the same everywhere and should be written once. But whether the result should run from low to high or high to low, and which field of a record decides the order, only the user of the class knows, and the user may not have been born when the sorting class was written.

The class cannot ask, and it should not guess. What it can do is declare an interface containing the one operation it lacks, take a reference of that interface type as an argument, and call it. Whoever uses the class writes a small class implementing the interface and hands over an object of it. The behaviour is supplied by the user; the sorting stays where it belongs.

sorting an array of marks in an order supplied by the user of the class Problem: Declare an interface Comparison with a method that reports whether two whole numbers are in the required order. Write a class Sorter that arranges an array using that method, without knowing what order it stands for. Write two classes implementing the interface, one for ascending order and one for descending, and use each in turn on an array of four marks. The array is fixed inside main(); no input is read.

// Purpose: to show a general class leaving one decision — the order of the
// sort — to a class supplied by the user through an interface.

interface Comparison
{
    boolean inOrder(int a, int b);
}

class Ascending implements Comparison
{
    public boolean inOrder(int a, int b)
    {
        return a <= b;
    }
}

class Descending implements Comparison
{
    public boolean inOrder(int a, int b)
    {
        return a >= b;
    }
}

class Sorter
{
    void sort(int x[], Comparison c)
    {
        for (int i = 0; i < x.length - 1; i++)
        {
            for (int j = 0; j < x.length - 1 - i; j++)
            {
                if (c.inOrder(x[j], x[j + 1]) == false)
                {
                    int t = x[j];
                    x[j] = x[j + 1];
                    x[j + 1] = t;
                }
            }
        }
    }

    void show(int x[])
    {
        String line = "" + x[0];
        for (int i = 1; i < x.length; i++)
        {
            line = line + " " + x[i];
        }
        System.out.println(line);
    }
}

class SortDemo
{
    public static void main(String args[])
    {
        int marks[] = {56, 91, 78, 63};
        Sorter s = new Sorter();

        s.sort(marks, new Ascending());
        s.show(marks);

        s.sort(marks, new Descending());
        s.show(marks);
    }
}

Sample output:

56 63 78 91
91 78 63 56

Variable description:

[Table:] Table 12.19 – variables of the sorting program, with their types and purposes [/Table] | Variable | Type | Purpose | |—|—|—| | x | int[] | formal argument referring to the array being sorted or displayed | | c | Comparison | formal argument holding the object that decides the order | | i, j | int | loop variables of the outer and inner loops | | t | int | temporary store used while exchanging two elements | | line | String | the line of output being built in show() | | marks | int[] | the array of four marks | | s | Sorter | the object that performs both sorts |

Notes: Sorter contains no < and no >. It compares nothing itself; it asks c whether two values are in order and acts on the answer. Reversing the whole sort therefore needs no change to Sorter at all — only a different object passed as the second argument, which is exactly what the two calls in main() do. Note also that show() reads x[0] before the loop, so it assumes the array holds at least one element; a class meant for general use would have to say so or check it.

the ascending sort of the array 56, 91, 78, 63

Outer pass i Comparisons made by inOrder(), and the action taken Array after the pass
0 (56, 91) in order, left alone; (91, 78) not in order, exchanged; (91, 63) not in order, exchanged 56, 78, 63, 91
1 (56, 78) in order, left alone; (78, 63) not in order, exchanged 56, 63, 78, 91
2 (56, 63) in order, left alone 56, 63, 78, 91

Result: the array leaves the method as 56, 63, 78, 91, which is the first line of the output. The trace shows that the only decision the sort ever makes is the one it gets back from inOrder() — replace that with the version in Descending and every exchange in the table reverses.

12.8.6 Abstract Class Compared with Interface

Both an abstract class and an interface state operations that other classes must supply, and neither can be used to create an object. They are not, however, alternatives to be chosen by taste.

Table 12.20 – an abstract class compared with an interface

Feature Abstract class Interface
Declared with abstract class interface
A class connects to it using extends implements
How many may one class take at most one any number
Methods it may contain both abstract methods and methods with bodies method declarations without bodies
Variables it may contain ordinary instance variables, of any access constants only, implicitly public static final
Constructors may have them, called by subclasses through super cannot have them
Objects of it cannot be created cannot be created
What it expresses what a thing is — a place in a family what a thing can do — a role

The last row is the one that decides between them in practice. Ask whether the classes involved are genuinely of one kind — the is-a test of Section 12.1.5. A rectangle and a triangle are both shapes, and share a name and a way of displaying themselves, so Shape is properly an abstract class. A cycle and a projector are not two kinds of one thing; they merely both happen to be rentable, so Rentable is properly an interface.

Nothing forbids using both at once, and the program of Section 12.8.4 did exactly that: Cycle took its identity from Equipment and its two roles from two interfaces.

12.8.7 The Java interface and the Everyday Word “Interface”

One caution closes the chapter, because the word carries two meanings in computer science and they are easily run together.

In ordinary usage, the interface of a class means the set of members it offers to the outside world — the public methods a user of the class may call, as against the private workings behind them. Every class has an interface in this sense, whether or not the keyword appears anywhere in the program. When a data structure is described as an abstract data type with a well-defined interface, it is this meaning that is intended.

In Java, interface is a keyword naming a particular construct: a declaration of constants and bodiless methods, written with interface, connected to a class with implements. It is one way of writing down an interface in the first sense, and a very disciplined one, since it forces every implementing class to provide exactly what was promised.

The relationship is worth stating exactly. Every Java interface describes an interface in the general sense. Not every interface in the general sense is a Java interface — the public methods of an ordinary class are its interface too. When you meet the word, ask which is meant; the keyword, in interface_name form and in a listing, always means the construct.

Practical link: implementing an interface through a class (Section 12.8.3) — file this under “Interfaces” in your work file. Declare an interface Fine holding a constant FREE_DAYS equal to 7 and declaring a method double fineFor(int days). Write two classes implementing it, IssuedBook charging 2 rupees and IssuedJournal charging 5 rupees for each day kept beyond the free days, with no fine at all within them. Read the kind of item and the number of days kept, and print the fine with a suitable message. Test your program with 5 days and with 7 days, and then with the unseen input 30 days.

12.9 Summary

Inheritance and its forms
  1. Inheritance is the mechanism by which one class acquires the data members and member methods of another, uses them as though it had declared them, and adds members of its own. The keyword is extends.
  2. The class whose description is acquired is the superclass, also called the base or parent class; the class acquiring it is the derived class, also called the subclass or child class. Only the derived class names the other.
  3. An object of a derived class holds the inherited members and the added ones together; it is one object, not two.
  4. A derived class inherits instance variables and member methods. It does not inherit constructors, it cannot directly reach private members, and it cannot alter the superclass.
  5. The gain is reusability: code written and tested once serves many classes, a correction in the superclass reaches every class below it, and inheritance is transitive down a chain. The cost is tight coupling — a change in the superclass ripples into classes its author never saw.
  6. Java supports single inheritance (one derived class, one superclass), hierarchical inheritance (several derived classes, one superclass) and multilevel or nested inheritance (a derived class itself extended). Hybrid inheritance is any combination of these.
  7. Multiple inheritance — one class extending two or more classes — is not allowed between classes in Java, because two superclasses could supply two bodies for the same method and there would be no honest way to choose. Interfaces serve where it is needed.
  8. Write B extends A only when the is-a relationship holds — when an object of B genuinely is an object of A. Where one class merely needs to use another, the has-a relationship is right: hold an object of it as a variable. Reuse is a benefit of inheritance, not a reason for it.
Member access in a derived class
  1. Every member has exactly one access specifier: private, default (none written), protected or public. Each level reaches one place further than the one above it.
  2. A private member is usable only inside its own class. It is present in every subclass object but is not accessible there by name.
  3. A member with no specifier is not public: it is usable throughout its own package only, and so is invisible to a derived class in another package.
  4. A protected member is usable in its own class, anywhere in its package, and in any derived class even outside the package.
  5. A public member is usable everywhere, by derived and unrelated classes alike.
  6. Java has no public or private mode of inheritance. Every inherited member keeps exactly the access it was given in the superclass.
  7. Where a derived class needs a private value of its superclass, the superclass supplies an accessor method (getter) to return it and, where it must be changed, a mutator method (setter) to receive it. Because the change then passes through a method of the superclass, conditions can still be enforced — which a protected variable cannot do.
Constructors in an inheritance chain
  1. A constructor is not inherited: it carries the name of its own class, and it exists to complete an object of that class, of whose added members it knows nothing.
  2. If a class declares no constructor, the compiler supplies a default constructor taking no arguments. The moment any constructor is declared, that supplied one disappears.
  3. super(...) invokes a constructor of the immediate superclass. It may appear only in a constructor and must be its first statement.
  4. If super(...) is not written, the compiler inserts a call to the superclass’s no-argument constructor. A superclass having only a parameterised constructor therefore causes a compile-time error unless super(...) is written explicitly.
  5. Constructors are entered from the bottom of the chain and completed from the top, so the most general part of an object is always finished first. Instance variables receive their default values — 0, false, null — before any constructor body runs.
Redefinition in subclasses
  1. Redefining an instance variable hides it: both variables exist in the object, the derived class’s own name refers to its own, and super.name reaches the inherited one. Code written in the superclass goes on using the superclass’s variable. Hiding is legal and almost always a mistake.
  2. Method overriding is the declaration in a derived class of a method with the same signature — name and parameter list — and the same return type as an inherited method, so that the derived class’s version is used for its objects.
  3. An overriding method may not be less accessible than the one it overrides, and a private method cannot be overridden at all.
  4. Change the parameter list and nothing is overridden; a second, unrelated method is declared, and the inherited one goes on being used. This error is silent.
  5. super.methodName(...) calls the superclass’s version of an overridden method. It is an ordinary statement and may stand anywhere in a method. Without super, the call names the method that is already running.
  6. Polymorphism is one name standing for more than one behaviour. Overloading — same name, different parameter lists, one class — is settled by the compiler from the arguments written, and is called compile-time polymorphism. Overriding is settled while the program runs and is called run-time polymorphism.
The class Object
  1. Every class in Java is descended from Object, which belongs to java.lang. A class declaring no superclass has Object as its immediate superclass, so all classes form one tree.
  2. Every object therefore inherits toString(), equals(), hashCode() and getClass() before its own class declares anything. Left unoverridden, toString() reports only the class name and a code, and equals() is true only for one and the same object.
  3. toString() is called automatically when an object is joined to a string or passed to println(), so overriding it makes a class printable everywhere.
  4. An overriding equals() must take an argument of type Object; declaring it of the class’s own type changes the signature and overrides nothing. A class that overrides equals() should override hashCode() with it.
  5. For objects, == compares references and asks whether they lead to one and the same object; equals() compares whatever the class decides, and compares references only when the class has not overridden it.
Subclass polymorphism and dynamic binding
  1. Subclass polymorphism is the ability of a superclass reference to refer to an object of any class derived from it, so that one variable, array element or argument handles several related classes. The reverse assignment is not allowed.
  2. The compiler checks every call against the declared type of the reference, so members added by a subclass are unreachable through a superclass reference. Reaching them needs an instanceof test followed by a cast.
  3. Dynamic binding is the choosing of the version of an overridden method while the program runs, from the class of the object rather than the type of the reference. It is also called late or run-time binding.
  4. Static or early binding is its opposite and governs instance variables and overloaded methods. In one sentence: through a superclass reference, variables come from the reference and methods come from the object.
  5. Polymorphism lets a new subclass be added without altering the code that uses the family, and lets related objects be held and processed uniformly. It also narrows what a reference can reach, makes a program harder to read at the point of call, and works only if the superclass was designed with the operation in it.
Abstract classes and abstract data types
  1. An abstract class is declared with abstract and no object of it can be created. It may still hold instance variables, ordinary methods and constructors, and its constructor is called by its subclasses through super. A class that is not abstract is a concrete class.
  2. A reference of an abstract class type is perfectly legal and may refer to any of its subclass objects.
  3. An abstract method is declared with abstract, has no body, and ends in a semicolon. A method with an empty pair of braces is not abstract; it is an ordinary method that does nothing.
  4. A class with even one abstract method must be declared abstract; every concrete subclass must override every abstract method it inherits, and a subclass that overrides only some must itself be abstract.
  5. Abstract methods turn a superclass’s hope that its subclasses will override a method into a requirement the compiler enforces.
  6. An abstract data type (ADT) is a type defined by the operations that may be performed on it and by what they do, not by how its data is stored or its operations carried out. Encapsulation hides the representation and abstract methods fix the operations. An abstract class gives only a partial ADT, since it also imposes data and ancestry.
Interfaces
  1. An interface is a named collection of constants and of method declarations without bodies. No object of it can be created and it has no constructor.
  2. Because it supplies no bodies, nothing can clash, so a class may take on any number of interfaces; and because it stands outside the inheritance tree, unrelated classes may share the role it names.
  3. A method declared in an interface is implicitly public and abstract. A variable declared in it is implicitly public, static and final — a constant that must be given its value where it is declared. An interface has no instance variables.
  4. A class states that it provides an interface’s methods with implements, and must define every one of them or be declared abstract itself. Those methods must be declared public, since an overriding method may not be less accessible.
  5. A class may extend at most one class and implement any number of interfaces, with extends written before implements. One interface may build on another, and the keyword for that is extends, not implements.
  6. An interface name is usable as a reference type, so dynamic binding extends across classes with no common ancestor. Such a reference can call only the methods the interface declares.
  7. An interface also lets the writer of a general class leave one decision to whoever uses it: the class works entirely through the interface, and the user supplies a class implementing it. This is what the syllabus means by an interface used for user defined implementation of behaviour.
  8. Choose between the two constructs by what they express. An abstract class says what a thing is and suits classes that form one family and share data; an interface says what a thing can do and suits classes that share only a capability, or that already have superclasses of their own.
  9. The word interface has two senses. In ordinary usage it means the set of public method prototypes a class offers, which every class has. In Java it names a construct declared with the keyword interface. The construct is one disciplined way of writing down an interface in the first sense.

12.10 Key Terms

  1. abstract — the Java keyword that marks a class as one whose objects cannot be created, or a method as one declared without a body.
  2. abstract class — a class declared with abstract, of which no object can be created, written to be extended by other classes.
  3. abstract data type (ADT) — a type defined by the operations that may be performed on it and by what they do, and not by how its data is stored or its operations are carried out.
  4. abstract method — a member method declared with abstract, having no body and ending in a semicolon, which every concrete subclass must override.
  5. access specifier — the keyword written before a member that fixes where in the program that member may be used: private, default, protected or public.
  6. accessor method — a method of a class that returns the value of one of that class’s own data members; also called a getter.
  7. ADT — abstract data type.
  8. cast — a class name written in brackets before a reference, telling the compiler to treat that reference as being of the named type.
  9. concrete class — a class that is not abstract, and of which objects can therefore be created.
  10. constructor — a member method carrying the same name as its class and having no return type, run automatically when an object is created, whose work is to initialise the data members.
  11. default constructor — the no-argument constructor the compiler supplies to a class that declares no constructor of its own.
  12. derived class — a class that acquires the members of another class by naming it with extends; also called the subclass or child class.
  13. dynamic binding — the choosing of the version of an overridden method while the program is running, from the class of the object rather than the type of the reference; also called late or run-time binding.
  14. encapsulation — keeping an object’s data inside the object and allowing the outside world to reach it only through the object’s own methods.
  15. equals() — a method inherited from Object that reports whether two objects are to be regarded as the same, comparing references unless the class overrides it.
  16. extends — the Java keyword by which a class names the one superclass whose members it acquires, and by which one interface builds on another.
  17. has-a relationship — the relationship in which one class holds an object of another as a data member and uses it, without claiming to be one.
  18. hierarchical inheritance — the form in which several derived classes extend the same superclass.
  19. hybrid inheritance — a structure combining more than one form of inheritance.
  20. implements — the Java keyword by which a class undertakes to supply the methods declared in one or more interfaces.
  21. inheritance — the mechanism by which one class acquires the data members and member methods of another class and may add members of its own.
  22. instanceof — an operator that reports whether the object referred to on its left belongs to the class or interface named on its right.
  23. interface — in Java, a construct declared with the keyword interface, holding constants and method declarations without bodies, which classes may implement; in ordinary usage, the set of public method prototypes a class offers to the outside world.
  24. is-a relationship — the relationship that must hold for inheritance to be sound: every object of the derived class must genuinely be an object of the superclass.
  25. method overloading — declaring several methods with the same name but different parameter lists, the compiler deciding between them from the arguments written.
  26. method overriding — declaring in a derived class a method with the same signature and return type as an inherited one, so that it is used in place of the inherited version for objects of that class.
  27. multilevel inheritance — the form in which a derived class is itself extended, so that the chain runs through more than one level; also called nested inheritance.
  28. multiple inheritance — one class extending two or more classes at once, which Java does not allow between classes.
  29. mutator method — a method of a class that receives a value and assigns it to one of that class’s own data members; also called a setter.
  30. Object — the class in java.lang from which every other class in Java is descended.
  31. package — a named group of classes kept together, in practice the folder in which they are compiled.
  32. parameterised constructor — a constructor that takes one or more arguments.
  33. polymorphism — one name standing for more than one behaviour; its two forms are compile-time polymorphism, produced by overloading, and run-time polymorphism, produced by overriding.
  34. protected visibility — the access given by protected, allowing a member to be used in its own class, anywhere in its package, and in any derived class even outside the package.
  35. reusability — the use of code written and tested once by many classes, without its being copied.
  36. signature — a method’s name together with the number, types and order of its parameters.
  37. single inheritance — the form in which one derived class extends one superclass.
  38. static binding — the settling of a call by the compiler, from the declared type of the reference; it governs instance variables and overloaded methods, and is also called early binding.
  39. subclass polymorphism — the ability of a superclass reference to refer to an object of any class derived from it.
  40. super — the Java keyword used with brackets to call a superclass constructor, and with a dot to call a superclass method or reach a hidden superclass variable.
  41. superclass — the class whose members are acquired by another through extends; also called the base class or parent class.
  42. toString() — a method inherited from Object that returns a String describing the object, called automatically when an object is printed or joined to a string.
  43. variable hiding — declaring in a derived class an instance variable with the same name as an inherited one, so that both exist in the object and the inherited one is reached with super.

12.11 Points to Ponder

  1. Code can be reused in two ways: a class may extend another, or it may simply hold an object of another as a data member and call its methods. The second way creates no dependence on the superclass, and nothing forces a change in one class to ripple into the other. What, then, does inheritance give in return for the dependence it creates — and can you describe a program in which that return is not worth the price?

  2. Java forbids a class to extend two classes, on the ground that two superclasses might supply two bodies for the same method with no honest way to choose between them. Yet a class may implement two interfaces that declare the same method, and it then writes one body serving both promises — which may suit one interface’s intentions better than the other’s. Has the language solved the problem of multiple inheritance, or moved it from the compiler to the programmer?

  3. Redefining an instance variable in a subclass is legal Java, produces two variables of the same name in one object, and is almost never what anybody wants. The designers of the language could have forbidden it, as they forbade so much else. Is there value in leaving a legal but unwise construct available, or should a language rule out what its designers know to be a mistake?

  4. Polymorphism is praised because a new subclass can be added without altering a line of the code that uses the family. But it also means that reading list[i].charge() tells you nothing whatever about what will be computed, since that depends on an object created somewhere else. Extensibility has been bought with readability — which of the two matters more, and does your answer change according to who will have to maintain the program next year?

  5. An abstract method turns a hope into a requirement: the superclass no longer trusts its subclasses to supply the operation, and the compiler refuses to proceed without it. Look through a program you have written and find something that is at present only a hope — a comment, a naming convention, an agreement between you and a classmate. Could it be turned into something the compiler checks, and what would be lost if it were?

  6. Every class in Java descends from Object, so every object you create carries toString(), equals() and hashCode() whether the class has any use for them or not. A class may redefine what equals() means for its own objects, but no class can redefine what == means. Would the language be better or worse if the meaning of == could be settled by each class in the same way?

12.12 Objective Questions

  1. Which one of the following is not inherited by a derived class from its superclass? [1 mark]
  1. a public member method
  2. a protected instance variable
  3. a constructor
  4. a method the superclass itself inherited from Object
  1. In Java, one class may extend ______ class or classes and implement ______ interface or interfaces. [1 mark]
  1. one; one
  2. one; any number of
  3. any number of; one
  4. any number of; any number of
  1. An overriding method may not: [1 mark]
  1. carry the same name as the method it overrides
  2. be less accessible than the method it overrides
  3. call the method it overrides
  4. belong to a class that declares a constructor
  1. Which one of the following statements about a Java interface is correct? [1 mark]
  1. It may declare instance variables.
  2. It may declare a constructor.
  3. Its methods are public whether the word is written or not.
  4. A class connects itself to it with extends.
  1. A Shape reference refers to a Circle object, and both classes declare a method area(). The version of area() that is carried out is settled by: [1 mark]
  1. the declared type of the reference, at compile time
  2. the class of the object, while the program is running
  3. the order in which the two classes were compiled
  4. the access specifier written on the method
  1. Assertion (A): A class whose only constructor is parameterised cannot be extended unless the subclass constructor writes a call to super(...) explicitly. Reason (R): When a constructor does not begin with super(...), the compiler inserts a call to the superclass’s no-argument constructor. [1 mark]
  1. Both A and R are true and R is the correct explanation of A.
  2. Both A and R are true but R is not the correct explanation of A.
  3. A is true but R is false.
  4. A is false but R is true.
  1. Assertion (A): An abstract class cannot be used as the type of a reference variable. Reason (R): No object of an abstract class can be created. [1 mark]
  1. Both A and R are true and R is the correct explanation of A.
  2. Both A and R are true but R is not the correct explanation of A.
  3. A is true but R is false.
  4. A is false but R is true.
  1. Match each keyword or operator in Column A with what it does, in Column B. [4 marks]
Column A Column B
a. extends i. undertakes to supply the methods an interface declares
b. implements ii. reports whether an object belongs to a given class
c. super iii. names the one class whose members are acquired
d. instanceof iv. reaches a member of the immediate superclass
  1. Fill in each blank with the correct term. [4 marks]
  1. A class that is not abstract is called a ______ class.
  2. The relationship that must hold for B extends A to be sound is the ______ relationship.
  3. A variable declared inside an interface is implicitly public, static and ______.
  4. Choosing the version of an overridden method while the program runs is called ______ binding.
  1. State whether each of the following is true or false. [4 marks]
  1. A private member of a superclass is present in a subclass object but cannot be used there by name.
  2. An abstract class must contain at least one abstract method.
  3. Method overloading is settled by the compiler from the arguments written at the call.
  4. One interface may extend another interface.
  1. Give the full form of ADT. [1 mark]

12.13 Check Your Concepts

  1. Define inheritance, and give the two names by which the class that acquires the members is known. [2 marks]

  2. What is meant by the signature of a method? State why it matters when a method is overridden. [2 marks]

  3. Name two things a derived class does not receive from its superclass. [2 marks]

  4. A member is declared with no access specifier at all. State where it may be used, and name one place where a protected member may be used but this one may not. [2 marks]

  5. Differentiate between method overloading and method overriding, giving any three points of difference. [3 marks]

  6. Differentiate between an abstract class and an interface, giving any three points of difference. [3 marks]

  7. Differentiate between == and equals() when both are applied to two object references. [3 marks]

  8. Give reasons why a constructor is not inherited by a derived class, and state how the inherited part of a subclass object is initialised instead. [3 marks]

  9. A superclass declares an instance variable and a subclass declares another of exactly the same name. Explain with a short example what the subclass object then contains, how each of the two variables is reached from inside the subclass, and which of them is used by a method whose body was written in the superclass. [4 marks]

  10. Explain why a superclass reference may refer to a subclass object while a subclass reference may not refer to a superclass object. State one restriction that such a superclass reference places on the programmer, and name the operator used to make it safe to remove that restriction. [4 marks]

  11. A superclass declares only a parameterised constructor, and a subclass constructor does not begin with a call to super(...). Explain what the compiler does in this situation, what it reports, and the two ways in which the program may be corrected. [4 marks]

  12. Explain what dynamic binding means. Using a superclass with one overridden method and two classes derived from it, show how a single statement inside a loop can produce different results for different objects. State two advantages of writing a program in this way and one honest limitation of it. [6 marks]

  13. An abstract class and an interface both oblige other classes to supply a method. Explain, with a suitable example of each, how that obligation is created in the two cases, and state two situations in which an interface is the better choice than an abstract class. [6 marks]

12.14 Output & Debugging

  1. Study the following classes.
class Alpha
{
    Alpha()
    {
        System.out.println("Alpha");
    }
}

class Beta extends Alpha
{
    Beta()
    {
        System.out.println("Beta");
    }
}

class Gamma extends Beta
{
    Gamma()
    {
        System.out.println("Gamma");
    }
}

Write the output produced by the statement Gamma g = new Gamma(); and explain in one line why the three lines appear in that order, although no super is written anywhere. [3 marks]

  1. Study the following classes.
class Reading
{
    int units = 50;

    void show()
    {
        System.out.println(units);
    }
}

class Meter extends Reading
{
    int units = 90;

    void display()
    {
        System.out.println(units);
        System.out.println(super.units);
    }
}

Write the three lines printed by Meter m = new Meter(); m.display(); m.show(); and state why the last line is what it is. [3 marks]

  1. Study the following classes.
class Charge
{
    void print()
    {
        System.out.println("ordinary charge");
    }
}

class LateCharge extends Charge
{
    void print()
    {
        System.out.println("late charge");
    }
}

State the output of the two statements Charge c = new LateCharge(); c.print(); and name the thing that decided which version was carried out. [2 marks]

  1. The following classes do not compile.
interface Signal
{
    String colour();
}

class StopSignal implements Signal
{
    String colour()
    {
        return "red";
    }
}

Identify the error, state the rule that has been broken, and rewrite the offending line correctly. [3 marks]

  1. The following classes compile, but the program stops with an error while it is running.
class Fare
{
    double amount()
    {
        return 100.0;
    }
}

class NightFare extends Fare
{
    double amount()
    {
        return amount() * 2;
    }
}

Name the fault, explain in one line why the program cannot finish, and rewrite the faulty statement so that a night fare of 200.0 is returned. [3 marks]

12.15 Programming Practice

  1. A superclass Face stores the length and the breadth of a rectangular face in decimals and has a method double area() that returns length × breadth. A class Carton derived from it adds a height, and must supply a method double surfaceArea() returning the total surface area of the carton, computed as 2 × (area of the face) + 2 × height × (length + breadth). The method must obtain the area of the face by calling the superclass’s method rather than repeating its formula. Assume that Face has protected instance variables and a parameterised constructor. Write only the class Carton, giving its constructor and its surfaceArea() method, followed by one line explaining why super is needed in it. The main() method need not be written. [4 marks]

  2. A superclass Item stores the details of an article sold at a school store, and a class Packet derived from it holds the number of such articles sold together.

Class Members
Item name (String), price (double); a parameterised constructor; void show() to display the name and the price
Packet count (int); a parameterised constructor that initialises the members of both classes; double packetPrice() returning price × count; void show() displaying the details of the item followed by the number of articles and the price of the packet

Specify the class Item, and using the concept of inheritance specify the class Packet. Submit both classes together with a variable description table. The main() method need not be written. [6 marks]

  1. Define an abstract class Journey holding a protected variable for the distance of a journey in kilometres, a parameterised constructor, an abstract method double fare() and an ordinary method void display() that prints the distance followed by the fare. Derive two classes from it: BusJourney, charging rupees 2.50 a kilometre, and TrainJourney, charging rupees 1.20 a kilometre together with a fixed reservation charge of rupees 40. Write the three classes and a main() method that creates one object of each kind and displays both journeys. Submit the algorithm for each fare() method, the three classes, main(), and a variable description table. Test your program with a distance of 20 km for each kind of journey. [6 marks]

  2. Define an interface Volume holding the constant PI equal to 3.142 and declaring one method double volume(). Write two classes that implement it: Cylinder, holding a radius and a height, whose volume is PI × radius × radius × height; and Cube, holding a side, whose volume is side × side × side. In main(), read the measurements with Scanner, store one object of each class in a single array of type Volume, and print the two volumes using one loop. Submit the interface, both classes, main(), and a variable description table, and state in one line why the array can hold objects of two classes that are not related by inheritance. [6 marks]