Bruce Eckel’s Thinking in Java | Contents | Prev | Next |
and
methods
all the instrument examples, the methods in the base class
Instrument
were always “dummy” methods. If these methods are ever called,
you’ve done something wrong. That’s because the intent of
Instrument
is to create a
common
interface
for all the classes derived from it.
only reason to establish this common interface
is so it can be expressed differently for each different subtype. It
establishes a basic form, so you can say what’s in common with all the
derived classes. Another way of saying this is to call
Instrument
an
abstract
base class
(or
simply an
abstract
class
).
You create an abstract class when you want to manipulate a set of classes
through this common interface. All derived-class methods that match the
signature of the base-class declaration will be called using the dynamic
binding mechanism. (However, as seen in the last section, if the method’s
name is the same as the base class but the arguments are different,
you’ve got overloading, which probably isn’t what you want.)
you have an abstract class like
Instrument,
objects of that class almost always have no meaning. That is,
Instrument
is meant to express only the interface, and not a particular implementation, so
creating an
Instrument
object makes no sense, and you’ll probably want to prevent the user from
doing it. This can be accomplished by making all the methods in
Instrument
print error messages, but this delays the information until run-time and
requires reliable exhaustive testing on the user’s part. It’s
always better to catch problems at compile time.
provides a mechanism for doing this called the
abstract
method
.
This is a method that is incomplete; it has only a declaration and no method
body. Here is the syntax for an abstract method declaration:
void X();
class containing abstract methods is called an
abstract
class
.
If a class contains one or more abstract methods, the class must be qualified as
abstract.
(Otherwise, the compiler gives you an error message.)
an abstract class is incomplete, what is the compiler supposed to do when
someone tries to make an object of that class? It cannot safely create an
object of an abstract class, so you get an error message from the compiler.
This way the compiler ensures the purity of the abstract class, and you
don’t need to worry about misusing it.
you inherit
from an abstract class and you want to make objects of the new type, you must
provide method definitions for all the abstract methods in the base class. If
you don’t (and you may choose not to), then the derived class is also
abstract and the compiler will force you to qualify
that
class with the abstract
keyword.
possible to declare a class as
abstract
without
including any
abstract
methods. This is useful when you’ve got a class in which it doesn’t
make sense to have any
abstract
methods, and yet you want to prevent any instances of that class.
Instrument
class can easily be turned into an abstract class. Only some of the methods
will be abstract, since making a class abstract doesn’t force you to make
all the methods abstract.
Here’s
what it looks like:
//: Music4.java // Abstract classes and methods import java.util.*; abstract class Instrument4 { int i; // storage allocated for each public abstract void play(); public String what() { return "Instrument4"; } public abstract void adjust(); } class Wind4 extends Instrument4 { public void play() { System.out.println("Wind4.play()"); } public String what() { return "Wind4"; } public void adjust() {} } class Percussion4 extends Instrument4 { public void play() { System.out.println("Percussion4.play()"); } public String what() { return "Percussion4"; } public void adjust() {} } class Stringed4 extends Instrument4 { public void play() { System.out.println("Stringed4.play()"); } public String what() { return "Stringed4"; } public void adjust() {} } class Brass4 extends Wind4 { public void play() { System.out.println("Brass4.play()"); } public void adjust() { System.out.println("Brass4.adjust()"); } } class Woodwind4 extends Wind4 { public void play() { System.out.println("Woodwind4.play()"); } public String what() { return "Woodwind4"; } } public class Music4 { // Doesn't care about type, so new types // added to the system still work right: static void tune(Instrument4 i) { // ... i.play(); } static void tuneAll(Instrument4[] e) { for(int i = 0; i < e.length; i++) tune(e[i]); } public static void main(String[] args) { Instrument4[] orchestra = new Instrument4[5]; int i = 0; // Upcasting during addition to the array: orchestra[i++] = new Wind4(); orchestra[i++] = new Percussion4(); orchestra[i++] = new Stringed4(); orchestra[i++] = new Brass4(); orchestra[i++] = new Woodwind4(); tuneAll(orchestra); } } ///:~
can see that there’s really no change except in the base class.