Presentation is loading. Please wait.

Presentation is loading. Please wait.

7: Polymorphism Upcasting revisited Forgetting the object type

Similar presentations


Presentation on theme: "7: Polymorphism Upcasting revisited Forgetting the object type"— Presentation transcript:

1 7: Polymorphism Upcasting revisited Forgetting the object type
The twist Method-call binding Producing the right behavior Extensibility Overriding vs. overloading Abstract classes and methods Constructors and polymorphism Designing with inheritance Exercises

2 7: Polymorphism Polymorphism is the third essential feature of an object-oriented programming language, after data abstraction and inheritance.

3 7: Polymorphism class Note { private int value;
private Note(int val) { value = val; } public static final Note MIDDLE_C = new Note(0), C_SHARP = new Note(1), B_FLAT = new Note(2); } // Etc. class Instrument { public void play(Note n) { System.out.println("Instrument.play()"); } // Wind objects are instruments // because they have the same interface: class Wind extends Instrument { // Redefine interface method: public void play(Note n) { System.out.println("Wind.play()"); } public class Music { public static void tune(Instrument i) { i.play(Note.MIDDLE_C); public static void main(String[] args) { Wind flute = new Wind(); tune(flute); // Upcasting

4 The twist 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 doesn’t 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 can’t.

5 Method-call binding Connecting a method call to a method body is called binding. early binding: When binding is performed before the program is run (by the compiler and linker) 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 that’s early binding. late binding: 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. There must be some mechanism to determine the type of the object at run-time and to call the appropriate method. The compiler still doesn’t know the object type.

6 Producing the right behavior
The classic example in OOP is the “shape” example. This is commonly used because it is easy to visualize.

7 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()"); } public class Shapes { public static Shape randShape() { // Upcasting switch((int)(Math.random() * 3)) { default: case 0: return new Circle(); case 1: return new Square(); case 2: return new Triangle(); } public static void main(String[] args) { Shape[] s = new Shape[9]; // Fill up the array with shapes: for(int i = 0; i < s.length; i++) s[i] = randShape(); // Make polymorphic method calls: for(int i = 0; i < s.length; i++) s[i].draw(); } ///:~ Circle.draw() Triangle.draw() Circle.draw() Circle.draw() Circle.draw() Square.draw() Triangle.draw() Square.draw() Square.draw()

8 Exercise ========= public class Shapes main class Shape {
void draw() {} void erase() {} void flash() { draw(); erase(); draw(); } } 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()"); } ========= public class Shapes main for(int i = 0; i < s.length; i++) s[i]. flash();

9 Extensibility Because of polymorphism, you can add as many new types as you want to the system without changing the tune( ) method. All these new classes work correctly with the old, unchanged tune( ) method.

10 import java.util.*; class Instrument { public void play() { System.out.println("Instrument.play()"); } public String what() { return "Instrument"; } public void adjust() {} } ===================== class Wind extends Instrument { public void play() { System.out.println("Wind.play()"); } public String what() { return "Wind"; } class Percussion extends Instrument { public void play() { System.out.println("Percussion.play()"); } public String what() { return "Percussion"; } class Stringed extends Instrument { ……} class Woodwind extends Wind { ……} class Brass extends Wind { ……} ========================== public class Music3 { // Doesn't care about type, so new types static void tune(Instrument i) { // ... i.play(); } static void tuneAll(Instrument[] e) { for(int i = 0; i < e.length; i++) tune(e[i]); } public static void main(String[] args) { Instrument[] orchestra = new Instrument[5]; int i = 0; // Upcasting during addition to the array: orchestra[i++] = new Wind(); orchestra[i++] = new Percussion(); orchestra[i++] = new Stringed(); orchestra[i++] = new Brass(); orchestra[i++] = new Woodwind(); tuneAll(orchestra); } ///:~

11 Overriding vs. overloading
class NoteX { public static final int MIDDLE_C = 0, C_SHARP = 1, C_FLAT = 2; } class InstrumentX { public void play(int NoteX) { System.out.println("InstrumentX.play()"); class WindX extends InstrumentX { // OOPS! Changes the method interface: public void play(NoteX n) { System.out.println("WindX.play(NoteX n)"); } public class WindError { public static void tune(InstrumentX i) { i.play(NoteX.MIDDLE_C); } public static void main(String[] args) { WindX flute = new WindX(); tune(flute); // Not the desired behavior! } ///:~

12 Abstract classes and methods
In above examples, the methods in the base class Instrument were always “dummy” methods. If these methods are ever called, you’ve done something wrong. The intent of Instrument is to create a common interface for all the classes derived from it. Java provides a mechanism for doing this called the abstract method. A class containing abstract method is a abstract class. abstract method is a method that is incomplete; it has only a declaration and no method body. abstract void f(); It cannot create an object of an abstract class If you inherit from an abstract class and you want to make objects of the new type, you must override (redefine) 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.

13 Abstract classes and methods
import java.util.*; abstract class Instrument { int i; // storage allocated for each public abstract void play(); public String what() { return "Instrument"; } public abstract void adjust(); } class Wind extends Instrument { public void play() { System.out.println("Wind.play()"); public String what() { return "Wind"; } public void adjust() {}

14 Designing with inheritance
Once you learn about polymorphism, it can seem that everything ought to be inherited because polymorphism is such a clever tool. This can burden your designs; A better approach is to choose composition first, when it’s not obvious which one you should use. A Stage object contains a reference to an Actor, which is initialized to a HappyActor object. At run-time, a reference for a SadActor object can be substituted in a and then the behavior produced by go( ) changes. Thus you gain dynamic flexibility at run-time. (This is also called the State Pattern. )

15 Designing with inheritance
// Dynamically changing the behavior of // an object via composition. abstract class Actor { abstract void act(); } class HappyActor extends Actor { public void act() { System.out.println("HappyActor"); } class SadActor extends Actor { public void act() { System.out.println("SadActor"); } class Stage { Actor a = new HappyActor(); void change() { a = new SadActor(); } void go() { a.act(); } public class Transmogrify { public static void main(String[] args) { Stage s = new Stage(); s.go(); // Prints "HappyActor" s.change(); s.go(); // Prints "SadActor" } ///:~

16 Downcasting and run-time type identification
While upcasting is a useful and sensible approach (depending on the situation) it has a drawback. The extended part of the interface in the derived class is not available from the base class, so once you upcast you can’t call the new methods:

17 Downcasting and run-time type identification
import java.util.*; class Useful { public void f() {} public void g() {} } class MoreUseful extends Useful { public void u() {} public void v() {} public void w() {} import java.util.*; public class RTTI { public static void main(String[] args) { Useful[] x = { new Useful(), new MoreUseful() }; x[0].f(); x[1].g(); // Compile-time: method not found in Useful: //! x[1].u(); // Downcast/RTTI ((MoreUseful)x[1]).u(); // Exception thrown ((MoreUseful)x[0]).u(); } } ///:~

18 Downcasting and run-time type identification
Since you lose the specific type information via an upcast (moving up the inheritance hierarchy), you can use a downcast to retrieve the type information (moving down the inheritance hierarchy ) An upcast is always safe; the base class cannot have a bigger interface than the derived class, therefore every message you send through the base class interface is guaranteed to be accepted. But a downcast is unsafe, A shape (for example) may be a circle or a triangle or a square or some other type. In Java every cast is checked! At run-time this cast is checked to ensure that it is in fact the type you think it is. If it isn’t, you get a ClassCastException. This act of checking types at run-time is called run-time type identification (RTTI).


Download ppt "7: Polymorphism Upcasting revisited Forgetting the object type"

Similar presentations


Ads by Google