Inheritance syntax

Bruce Eckel’s Thinking in Java Contents | Prev | Next

Inheritance
is such an integral part of Java (and OOP languages in general) that it was
introduced in Chapter 1 and has been used occasionally in chapters before this
one because certain situations required it. In addition, you’re always
doing inheritance when you create a class, because if you don’t say
otherwise you inherit from Java’s standard root class
Object.

//: Detergent.java
// Inheritance syntax & properties
 
class Cleanser {
  private String s = new String("Cleanser");
  public void append(String a) { s += a; }
  public void dilute() { append(" dilute()"); }
  public void apply() { append(" apply()"); }
  public void scrub() { append(" scrub()"); }
  public void print() { System.out.println(s); }
  public static void main(String[] args) {
    Cleanser x = new Cleanser();
    x.dilute(); x.apply(); x.scrub();
    x.print();
  }
}
 
public class Detergent extends Cleanser {
  // Change a method:
  public void scrub() {
    append(" Detergent.scrub()");
    super.scrub(); // Call base-class version
  }
  // Add methods to the interface:
  public void foam() { append(" foam()"); }
  // Test the new class:
  public static void main(String[] args) {
    Detergent x = new Detergent();
    x.dilute();
    x.apply();
    x.scrub();
    x.foam();
    x.print();
    System.out.println("Testing base class:");
    Cleanser.main(args);
  }
} ///:~ 

This
demonstrates a number of features. First, in the
Cleanser
append( )
method,
Strings
are concatenated to
s
using the
+=
operator, which is one of the operators (along with ‘
+’)
that the Java designers “overloaded” to work with Strings.

Here,
you can see that
Detergent.main( )
calls
Cleanser.main( )
explicitly.

It’s
important that all of the methods in
Cleanser
are
public.
Remember that if you leave off any access specifier the member defaults to
“friendly,” which allows access only to package members. Thus,
within this package, anyone could use those methods if there were no access
specifier.
Detergent
would have no trouble, for example. However, if a class from some other package
were to inherit
Cleanser
it could access only
public
members.
So to plan for inheritance, as a general rule make all fields
private
and
all methods
public.
(protected
members
also allow access by derived classes; you’ll learn about this later.) Of
course, in particular cases you must make adjustments, but this is a useful
guideline.

When
inheriting you’re not restricted to using the methods of the base class.
You can also add new methods to the derived class exactly the way you put any
method in a class: just define it. The
extends
keyword
suggests that you are going to add new methods to the base-class interface, and
the method
foam( )
is an example of this.

Initializing
the base class

Of
course, it’s essential that the base-class subobject be initialized
correctly and there’s only one way to guarantee that: perform the
initialization in the constructor, by calling the base-class constructor, which
has all the appropriate knowledge and privileges to perform the base-class
initialization. Java automatically inserts calls to the base-class constructor
in the derived-class constructor. The following example shows this working with
three levels of inheritance:

//: Cartoon.java
// Constructor calls during inheritance
 
class Art {
  Art() {
    System.out.println("Art constructor");
  }
}
 
class Drawing extends Art {
  Drawing() {
    System.out.println("Drawing constructor");
  }
}
 
public class Cartoon extends Drawing {
  Cartoon() {
    System.out.println("Cartoon constructor");
  }
  public static void main(String[] args) {
    Cartoon x = new Cartoon();
  }
} ///:~ 

The
output for this program shows the automatic calls:

Art constructor
Drawing constructor
Cartoon constructor

You
can see that the construction happens from the base “outward,” so
the base class is initialized before the derived-class constructors can access
it.

Even
if you don’t create a constructor for
Cartoon( ),
the compiler will synthesize
a default constructor for you that calls the base class constructor.


Constructors
with arguments

//: Chess.java
// Inheritance, constructors and arguments
 
class Game {
  Game(int i) {
    System.out.println("Game constructor");
  }
}
 
class BoardGame extends Game {
  BoardGame(int i) {
    super(i);
    System.out.println("BoardGame constructor");
  }
}
 
public class Chess extends BoardGame {
  Chess() {
    super(11);
    System.out.println("Chess constructor");
  }
  public static void main(String[] args) {
    Chess x = new Chess();
  }
} ///:~ 

If
you don’t call the base-class constructor in
BoardGame( ),
the compiler will complain that it can’t find a constructor of the form
Game( ).
In addition, the call to the base-class constructor
must
be the first thing you do in the derived-class constructor. (The compiler will
remind you if you get it wrong.)


Catching
base constructor exceptions

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read