text: Polymorphism. Feedback
  Encapsulation creates new data types by combining characteristics and behaviors. Implementation hiding separates the interface from the implementation by making the details private. This sort of mechanical organization makes ready sense to someone with a procedural programming background. But polymorphism deals with decoupling in terms of types. In the last chapter, polymorphic method call allows one type to express its distinction from another, similar type, as long as theyre both derived from the same base type. This distinction is expressed through differences in behavior of the methods that you can call through the base class. Feedback
  In this chapter, youll learn about polymorphism (also called dynamic binding or late binding or run-time binding) starting from the basics, with simple examples that strip away everything but the polymorphic behavior of the program. Feedback
  In Chapter 6 you saw how an object can be used as its own type or as an object of its base type. Taking an object reference and treating it as a reference to its base type is called upcasting because of the way inheritance trees are drawn with the base class at the top. Feedback
  You also saw a problem arise, which is embodied in the following example about musical instruments. Since several examples play Notes, we should create the Note class separately, in a package:
  //: c07:music:Note.java // Notes to play on musical instruments. package c07.music; import com.bruceeckel.simpletest.*; public class Note { private String noteName; private Note(String noteName) { this.noteName = noteName; } public String toString() { return noteName; } public static final Note MIDDLE_C = new Note("Middle C"), C_SHARP = new Note("C Sharp"), B_FLAT = new Note("B Flat"); // Etc. } ///:~
  This is an enumeration class, which has a fixed number of constant objects to choose from. You cant make additional objects because the constructor is private.
  In the following example, Wind is a type of Instrument, therefore Wind is inherited from Instrument:
  //:" }); } } ///:~
  //: c07:music:Wind.java package c07.music; // Wind objects are instruments // because they have the same interface: public class Wind extends Instrument { // Redefine interface method: public void play(Note n) { System.out.println("Wind.play() " + n); } } ///:~
  //:" }); } } ///:~
  The method Music.tune( ) accepts an Instrument reference, but also anything derived from Instrument. In main( ), you can see this happening as a Wind reference is passed to tune( ), with no cast necessary. This is acceptablethe interface in Instrument must exist in Wind, because Wind is inherited from Instrument. Upcasting from Wind to Instrument may narrow that interface, but it cannot make it anything less than the full interface to Instrument. Feedback
  Music.java might seem strange to you. Why should anyone intentionally forget the type of an object? This is what happens when you upcast, and it seems like it could be much more straightforward if tune( ) simply takes a Wind reference as its argument. This brings up an essential point: If you did that, youd need to write a new tune( ) for every type of Instrument in your system. Suppose we follow this reasoning and add Stringed and Brass instruments: Feedback
  //: c07:music:Music2.java // Overloading instead of upcasting. package c07.music; import com.bruceeckel.simpletest.*; class Stringed extends Instrument { public void play(Note n) { System.out.println("Stringed.play() " + n); } } class Brass extends Instrument { public void play(Note n) { System.out.println("Brass.play() " + n); } } public class Music2 { private static Test monitor = new Test(); public static void tune(Wind i) { i.play(Note.MIDDLE_C); } public static void tune(Stringed i) { i.play(Note.MIDDLE_C); } public static void tune(Brass i) { i.play(Note.MIDDLE_C); } public static void main(String[] args) { Wind flute = new Wind(); Stringed violin = new Stringed(); Brass frenchHorn = new Brass(); tune(flute); // No upcasting tune(violin); tune(frenchHorn); monitor.expect(new String[] { "Wind.play() Middle C", "Stringed.play() Middle C", "Brass.play() Middle C" }); } } ///:~
  This works, but theres a major drawback: you must write type-specific methods for each new Instrument class you add. This means more programming in the first place, but it also means that if you want to add a new method like tune( ) or a new type of Instrument, youve got a lot of work to do. Add the fact that the compiler wont give you any error messages if you forget to overload one of your methods and the whole process of working with types becomes unmanageable. Feedback
  Wouldnt it be much nicer if you could just write a single method that takes the base class as its argument, and not any of the specific derived classes? That is, wouldnt it be nice if you could forget that there are derived classes, and write your code to talk only to the base class? Feedback
  Thats exactly what polymorphism allows you to do. However, most programmers who come from a procedural programming background have a bit of trouble with the way polymorphism works. Feedback
  The difficulty with Music.java can be seen by running the program. The output is Wind.play( ). This is clearly the desired output, but it doesnt seem to make sense that it would work that way. Look at the tune( ) method:
  public static void tune(Instrument i) { // ... i.play(Note.MIDDLE_C); }
  It receives an Instrument reference. So how can the compiler possibly know that this Instrument reference points to a Wind in this case and not a Brass or Stringed? The compiler cant. To get a deeper understanding of the issue, its helpful to examine the subject of binding. Feedback
  Connecting a method call to a method body is called binding. When binding is performed before the program is run (by the compiler and linker, if there is one), its called early binding. You might not have heard the term before because it has never been an option with procedural languages. C compilers have only one kind of method call, and thats early binding. Feedback
  The confusing part of the preceding program revolves around early binding, because the compiler cannot know the correct method to call when it has only an Instrument reference. Feedback
  The solution is called late binding, which means that the binding occurs at run time, based on the type of object. Late binding is also called dynamic binding or run-time binding. When a language implements late binding, there must be some mechanism to determine the type of the object at run time and to call the appropriate method. That is, the compiler still doesnt know the object type, but the method-call mechanism finds out and calls the correct method body. The late-binding mechanism varies from language to language, but you can imagine that some sort of type information must be installed in the objects. Feedback
  All method binding in Java uses late binding unless the method is static or final (private methods are implicitly final). This means that ordinarily you dont need to make any decisions about whether late binding will occurit happens automatically. Feedback
  Why would you declare a method final? As noted in the last chapter, it prevents anyone from overriding that method. Perhaps more important, it effectively turns off dynamic binding, or rather it tells the compiler that dynamic binding isnt necessary. This allows the compiler to generate slightly more efficient code for final method calls. However, in most cases it wont make any overall performance difference in your program, so its best to only use final as a design decision, and not as an attempt to improve performance. Feedback
  Once you know that all method binding in Java happens polymorphically via late binding, you can write your code to talk to the base class and know that all the derived-class cases will work correctly using the same code. Or to put it another way, you send a message to an object and let the object figure out the right thing to do. Feedback
  The classic example in OOP is the shape example. This is commonly used because it is easy to visualize, but unfortunately it can confuse novice programmers into thinking that OOP is just for graphics programming, which is of course not the case. Feedback
  The shape example has a base class called Shape and various derived types: Circle, Square, Triangle, etc. The reason the example works so well is that its easy to say a circle is a type of shape and be understood. The inheritance diagram shows the relationships: Feedback
  The upcast could occur in a statement as simple as:
  Shape s = new Circle();
  Here, a Circle object is created, and the resulting reference is immediately assigned to a Shape, which would seem to be an error (assigning one type to another); and yet its fine because a Circle is a Shape by inheritance. So the compiler agrees with the statement and doesnt issue an error message. Feedback
  Suppose you call one of the base-class methods (that have been overridden in the derived classes):
  s.draw();
  Again, you might expect that Shapes draw( ) is called because this is, after all, a Shape referenceso how could the compiler know to do anything else? And yet the proper Circle.draw( ) is called because of late binding (polymorphism). Feedback
  The following example puts it a slightly different way:
  //: c07:Shapes.java // Polymorphism in Java. import com.bruceeckel.simpletest.*; import java.util.*; class Shape { void draw() {} void erase() {} } class Circle extends Shape { void draw() { System.out.println("Circle.draw()"); } void erase() { System.out.println("Circle.erase()"); } } class Square extends Shape { void draw() { System.out.println("Square.draw()"); } void erase() { System.out.println("Square.erase()"); } } class Triangle extends Shape { void draw() { System.out.println("Triangle.draw()"); } void erase() { System.out.println("Triangle.erase()"); } } // A "factory" that randomly creates shapes: class RandomShapeGenerator { private Random rand = new Random(); public Shape next() { switch(rand.nextInt(3)) { default: case 0: return new Circle(); case 1: return new Square(); case 2: return new Triangle(); } } } public class Shapes { private static Test monitor = new Test();(); monitor.expect(new Object[] { new TestExpression("%% (Circle|Square|Triangle)" + "\\.draw\\(\\)", s.length) }); } } ///:~
  The base class Shape establishes the common interface to anything inherited from Shapethat is, all shapes can be drawn and erased. The derived classes override these definitions to provide unique behavior for each specific type of shape. Feedback
  RandomShapeGenerator is a kind of factory that produces a reference to a randomly-selected Shape object each time you call its next( ) method. Note that the upcasting happens in the return statements, each of which takes a reference to a Circle, Square, or Triangle and sends it out of next( ) as the return type, Shape. So whenever you call next( ), you never get a chance to see what specific type it is, since you always get back a plain Shape reference. Feedback
  main( ) contains an array of Shape references filled through calls to RandomShapeGenerator.next( ). At this point you know you have Shapes, but you dont know anything more specific than that (and neither does the compiler). However, when you step through this array and call draw( ) for each one, the correct type-specific behavior magically occurs, as you can see from the output when you run the program. Feedback
  The point of choosing the shapes randomly is to drive home the understanding that the compiler can have no special knowledge that allows it to make the correct calls at compile time. All the calls to draw( ) must be made through dynamic binding. Feedback
  Now. Feedback: Feedback
  //:. Feedback
  In main( ), when you place something inside the orchestra array, you automatically upcast to Instrument. Feedback. Feedback
  Heres something you might innocently try to do:
  //: c07:PrivateOverride.java // Abstract classes and methods. import com.bruceeckel.simpletest.*; public class PrivateOverride { private static Test monitor = new Test(); private void f() { System.out.println("private f()"); } public static void main(String[] args) { PrivateOverride po = new Derived(); po.f(); monitor.expect(new String[] { "private f()" }); } } class Derived extends PrivateOverride { public void f() { System.out.println("public f()"); } } ///:~
  You might reasonably expect the output to be public f( ), but a private method is automatically final, and is also hidden from the derived class. So Deriveds f( ) in this case is a brand new method; its not even overloaded, since the base-class version of f( ) isnt visible in Derived. Feedback
  The result of this is that only non-private methods may be overridden, but you should watch out for the appearance of overriding private methods, which generates no compiler warnings, but doesnt do what you might expect. To be clear, you should use a different name from a private base-class method in your derived class. Feedback
  In all the instrument examples, the methods in the base class Instrument were always dummy methods. If these methods are ever called, youve done something wrong. Thats because the intent of Instrument is to create a common interface for all the classes derived from it. Feedback
  The 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 whats 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 methods name is the same as the base class but the arguments are different, youve got overloading, which probably isnt what you want.) Feedback
  If 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 youll probably want to prevent the user from doing it. This can be accomplished by making all the methods in Instrument print error messages, but that delays the information until run time and requires reliable exhaustive testing on the users part. Its better to catch problems at compile time. Feedback
  Java provides a mechanism for doing this called the abstract method.[32] 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:
  abstract void f();
  A class containing abstract methods is called an abstract class. If a class contains one or more abstract methods, the class itself must be qualified as abstract. (Otherwise, the compiler gives you an error message.) Feedback
  If 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 dont need to worry about misusing it. Feedback
  If 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 dont (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. Feedback
  Its possible to create a class as abstract without including any abstract methods. This is useful when youve got a class in which it doesnt make sense to have any abstract methods, and yet you want to prevent any instances of that class. Feedback
  The Instrument class can easily be turned into an abstract class. Only some of the methods will be abstract, since making a class abstract doesnt force you to make all the methods abstract. Heres what it looks like:
  Heres the orchestra example modified to use abstract classes and methods:
  //: c07:music4:Music4.java // Abstract classes and methods. package c07.music4; import com.bruceeckel.simpletest.*; import java.util.*; import c07.music.Note; abstract class Instrument { private int i; // Storage allocated for each public abstract void play(Note n); public String what() { return "Instrument"; } public abstract void adjust(); } class Wind extends Instrument { public void play(Note n) { System.out.println("Wind.play() " + n); } public String what() { return "Wind"; } public void adjust() {} } class Percussion extends Instrument { public void play(Note n) { System.out.println("Percussion.play() " + n); } public String what() { return "Percussion"; } public void adjust() {} } class Stringed extends" }); } } ///:~
  You can see that theres really no change except in the base class. Feedback
  Its helpful to create abstract classes and methods because they make the abstractness of a class explicit, and tell both the user and the compiler how it was intended to be used. Feedback
  As usual, constructors are different from other kinds of methods. This is also true when polymorphism is involved. Even though constructors are not polymorphic (theyre actually static methods, but the static declaration is implicit), its important to understand the way constructors work in complex hierarchies and with polymorphism. This understanding will help you avoid unpleasant entanglements. Feedback
  The order of constructor calls was briefly discussed in Chapter 4 and again in Chapter 6, but that was before polymorphism was introduced. Feedback
  A constructor for the base class is always called during the construction process for a derived class, chaining up the inheritance hierarchy, its essential that all constructors get called, otherwise the entire object wouldnt be constructed. Thats why the compiler enforces a constructor call for every portion of a derived class. It will silently call the default constructor if you dont explicitly call a base-class constructor in the derived-class constructor body. If there is no default constructor, the compiler will complain. (In the case where a class has no constructors, the compiler will automatically synthesize a default constructor.) Feedback
  Lets take a look at an example that shows the effects of composition, inheritance, and polymorphism on the order of construction:
  //: c07:Sandwich.java // Order of constructor calls. package c07; import com.bruceeckel.simpletest.*;()");} } public class Sandwich extends PortableLunch { private static Test monitor = new Test(); private Bread b = new Bread(); private Cheese c = new Cheese(); private Lettuce l = new Lettuce(); public Sandwich() { System.out.println("Sandwich()"); } public static void main(String[] args) { new Sandwich(); monitor.expect(new String[] { "Meal()", "Lunch()", "PortableLunch()", "Bread()", "Cheese()", "Lettuce()", "Sandwich()" }); } } ///:~
  This example creates a complex class out of other classes, and each class has a constructor that announces itself. The important class is Sandwich, which reflects three levels of inheritance (four, if you count the implicit inheritance from Object) and three member objects. You can see the output when a Sandwich object is created in main( ). This means that the order of constructor calls for a complex object is as follows: Feedback preceding example). If you follow this practice, you will help ensure that all base class members and member objects of the current object have been initialized. Unfortunately, this doesnt handle every case, as you will see in the next section. Feedback
  When using composition and inheritance to create a new class, most of the time you wont have to worry about cleaning up; subobjects can usually be left to the garbage collector. If you do have cleanup issues, you must be diligent and create a dispose( ) method (the name I have chosen to use here; you may come up with something better) for your new class. And with inheritance, you must override dispose( ) in the derived class if you have any special cleanup that must happen as part of garbage collection. When you override dispose( ) in an inherited class, its important to remember to call the base-class version of dispose( ), since otherwise the base-class cleanup will not happen. The following example demonstrates this:
  //: c07:Frog.java // Cleanup and inheritance. import com.bruceeckel.simpletest.*; class Characteristic { private String s; Characteristic(String s) { this.s = s; System.out.println("Creating Characteristic " + s); } protected void dispose() { System.out.println("finalizing Characteristic " + s); } } class Description { private String s; Description(String s) { this.s = s; System.out.println("Creating Description " + s); } protected void dispose() { System.out.println("finalizing Description " + s); } } class LivingCreature { private Characteristic p = new Characteristic("is alive"); private Description t = new Description("Basic Living Creature"); LivingCreature() { System.out.println("LivingCreature()"); } protected void dispose() { System.out.println("LivingCreature dispose"); t.dispose(); p.dispose(); } } class Animal extends LivingCreature { private Characteristic p= new Characteristic("has heart"); private Description t = new Description("Animal not Vegetable"); Animal() { System.out.println("Animal()"); } protected void dispose() { System.out.println("Animal dispose"); t.dispose(); p.dispose(); super.dispose(); } } class Amphibian extends Animal { private Characteristic p = new Characteristic("can live in water"); private Description t = new Description("Both water and land"); Amphibian() { System.out.println("Amphibian()"); } protected void dispose() { System.out.println("Amphibian dispose"); t.dispose(); p.dispose(); super.dispose(); } } public class Frog extends Amphibian { private static Test monitor = new Test(); private Characteristic p = new Characteristic("Croaks"); private Description t = new Description("Eats Bugs"); public Frog() { System.out.println("Frog()"); } protected void dispose() { System.out.println("Frog dispose"); t.dispose(); p.dispose(); super.dispose(); } public static void main(String[] args) { Frog frog = new Frog(); System.out.println("Bye!"); frog.dispose(); monitor.expect(new String[] { "Creating Characteristic is alive", "Creating Description Basic Living Creature", "LivingCreature()", "Creating Characteristic has heart", "Creating Description Animal not Vegetable", "Animal()", "Creating Characteristic can live in water", "Creating Description Both water and land", "Amphibian()", "Creating Characteristic Croaks", "Creating Description Eats Bugs", "Frog()", "Bye!", "Frog dispose", "finalizing Description Eats Bugs", "finalizing Characteristic Croaks", "Amphibian dispose", "finalizing Description Both water and land", "finalizing Characteristic can live in water", "Animal dispose", "finalizing Description Animal not Vegetable", "finalizing Characteristic has heart", "LivingCreature dispose", "finalizing Description Basic Living Creature", "finalizing Characteristic is alive" }); } } ///:~
  Each class in the hierarchy also contains a member objects of types Characteristic and Description, which must also be disposed. The order of disposal should be the reverse of the order of initialization, in case one subobject is dependent on another. For fields, this means the reverse of the order of declaration (since fields are initialized in declaration order). For base classes (following the form thats used in C++ for destructors), you should perform the derived-class cleanup first, then the base-class cleanup. Thats because the derived-class cleanup could call some methods in the base class that require the base-class components to be alive, so you must not destroy them prematurely. From the output you can see that all parts of the Frog object are disposed in reverse order of creation. Feedback
  From this example, you can see that although you dont always need to perform cleanup, when you do, the process requires care and awareness. Feedback
  The. Feedback
  This is not exactly the case. If you call a dynamically-bound method inside a constructor, the overridden definition for that method is used. However, the effect can be rather unexpected and can conceal some difficult-to-find bugs. Feedback. Feedback. Feedback
  The order of initialization described in the earlier section isnt quite complete, and thats the key to solving the mystery. The actual process of initialization is:
  Theres an upside to this, which is that everything is at least initialized to zero (or whatever zero means for that particular data type) and not just left as garbage. This includes object references that are embedded inside a class via composition, which become null. So if you forget to initialize that reference, youll get an exception at run time. Everything else gets zero, which is usually a telltale value when looking at output. Feedback. Feedback. Feedback
  Once. Feedback. Feedback.. Feedback. Feedback. Feedback
  Since. Feedback
  To solve this problem, there must be some way to guarantee that a downcast is correct, so that you wont accidentally cast to the wrong type and then send a message that the object cant accept. This would be quite unsafe. Feedback. Feedback. Feedback
  Theres more to RTTI than a simple cast. For example, theres a way to see what type youre dealing with before you try to downcast it. All of Chapter 10 is devoted to the study of different aspects of Java run-time type identification. Feedback
  Polymorphism means different forms. In object-oriented programming, you have the same face (the common interface in the base class) and different forms using that face: the different versions of the dynamically bound methods. Feedback
  Youve seen in this chapter that its impossible to understand, or even create, an example of polymorphism without using data abstraction and inheritance. Polymorphism is a feature that cannot be viewed in isolation (like a switch statement can, for example), but instead works only in concert, as part of a big picture of class relationships. People are often confused by other, non-object-oriented features of Java, like method overloading, which are sometimes presented as object-oriented. Dont be fooled: If it isnt late binding, it isnt polymorphism. Feedback
  To use polymorphismand thus object-oriented techniqueseffectively in your programs, you must expand your view of programming to include not just members and messages of an individual class, but also the commonality among classes and their relationships with each other. Although this requires significant effort, its a worthy struggle, because the results are faster program development, better code organization, extensible programs, and easier code maintenance. Feedback
  Solutions to selected exercises can be found in the electronic document The Thinking in Java Annotated Solution Guide, available for a small fee from.
  [32] For C++ programmers, this is the analogue of C++s pure virtual function.