200 likes | 247 Views
Java Programming: From the Ground Up. Chapter 13: Polymorphism. Polymorphism. Polymorphism is the third fundamental concept of OOP. In contrast to inheritance, polymorphism underscores the differences of class behavior in an inheritance hierarchy. Ad-hoc Polymorphism – Method Overloading.
E N D
Java Programming:From the Ground Up Chapter 13: Polymorphism
Polymorphism • Polymorphism is the third fundamental concept of OOP. • In contrast to inheritance, polymorphismunderscores the differences of class behavior in an inheritance hierarchy.
Ad-hoc Polymorphism – Method Overloading • The code segment overloads the constructor of a Song class. • The constructor is polymorphic; the constructor has three forms. • public class Song • { • private String composer; • private String lyricist; • public Song () // default constructor • { • composer ="" ; • lyricist = ""; • } • public Song(String name) // same person wrote words and music • { • composer =name ; • lyricist = name; • } • public Song (String name1, String name2) // two songwriters • { • composer =name1; • lyricist = name2; • } • // other Song methods go here....... • } • Method overloading, a form of polymorphism, is also known as ad-hoc polymorphism.
Upcasting • Upcasting in an inheritance hierarchy allows an object of a derived type to be considered an object of a base type. Dog elvis; elvis = new HoundDog(); elvis = new Beagle(); elvis = new Bassett(); • Because a HoundDog is-a Dog, a HoundDog reference can be upcast to Dog (line 2). • Similarly, a Beagle reference and a Bassett reference can also be considered Dog references (lines 3 and 4). • The reference elvis is polymorphic, i.e., elvis has “many forms” and elvis can refer to a Dog object, a HoundDog object, a Beagle object, or a Bassett object.
Dynamic (or Late) Binding • A third form of polymorphism, dynamic or late binding, accentuates the behavioral differences among objects of different classes in a hierarchy. • This is in contrast to inheritance, which exploits the similarities of classes.
The Shape Hierarchy • Each class of the Shape hierarchy encapsulates a different geometrical shape. • Some typical shapes are:
The Shape Hierarchy Problem Statement: • Design classes Square, RightTriangle, and Triangle that encapsulate three geometrical shapes. Each class should implement a method void draw (int x, int y) that “draws” a square, a right triangle, or an equilateral triangle (a triangle with three equal sides), respectively. • The parameters x and y specify the relative position of the figure: y lines down and x spaces across from the current position of the screen cursor. • The instance variables of each class are: • int rows, the number of rows that comprise the figure, and • char character, the keyboard character used for drawing the figure.
The Shape Hierarchy Java Solution: • There is much the same about the three classes: the attributes are the same, and except for the draw(...) method, the getter and setter methods are the same. • Factor out the commonality of the classes into one (abstract) superclass, Shape, which serves as a base class in an inheritance hierarchy that includes Square, RightTriangle, and Triangle.
The Shape Hierarchy The Shape hierarchy
The Shape Hierarchy • The abstract class Shape has the following form: • public abstract class Shape • { • protected int rows; // figure drawn on rows rows • protected char character; // the drawing character • public Shape() • { • rows = 0; • char character = ' '; • } • public Shape(int x, char ch) • { • rows = x; • character = ch; • } • public int getRows() • { • return rows; • } • public char getCharacter() • { • return character; • } • public void setRows(int y) • { • rows = y; • } • public void setCharacter(char ch) • { • character = ch; • } • public abstract void draw(int x, int y); // must be implemented in concrete subclasses • }
The Shape Hierarchy Problem Statement: • Devise a test class that interactively queries a user for one of three shapes and subsequently draws the requested shape. Java Solution: • Themain(...) method of the following test class, requests input 1, 2, or 3 representing a square, a right triangle or an equilateral triangle, respectively. • Because a Square is-a Shape, a RightTriangle is-a Shape, and a Triangle is-a Shape, all references are upcast to Shape
The Shape Hierarchy • import java.util.*; • public class TestDraw • { • public static void main(String[] args) • { • Scanner input = new Scanner(System.in); • Shape shape = null; // all references can be upcast to Shape • int shapeNumber; //code number for each type of figure • System.out.print("Enter 1: Square, 2: RightTriangle, 3: Equilateral Triangle: "); • shapeNumber = input.nextInt(); • switch (shapeNumber) • { • case 1 : shape = new Square(4,'*'); //size 4, draw with * • break; • case 2 : shape = new RightTriangle(5,'#'); //size 5, draw with # • break; • case 3 : shape = new Triangle(6,'+'); //size 6, draw with + • break; • default : System.out.println("Invalid entry"); // shapeNumber is not 1,2, or 3 • System.exit(0); // bad data, terminate the application • } • shape.draw(1,1); • } • }
The Shape Hierarchy Discussion: • The application runs as you might expect, but only because Java implements polymorphism through late binding. • On line 22, it appears that a Shape object (shape) invokes its draw(…) method. • Shape is an abstract class, so no Shape object can exist. • Shape does not implement draw(...) as part of the Shape class, draw(...) is declared abstract. • Which draw(...) method is invoked? • The reference variable shape could refer to • a Square object (line 13), • a RightTriangle object (line 15), or • a Triangle object (line 17).
The Shape Hierarchy • When TestDraw is compiled and translated into bytecode, the Java compiler cannot determine which draw(…) method is applicable. • The compiler knows that shape refers to a kind of Shape, but it does not know which kind. • The appropriate draw(...) method is not discernible until the program runs and the user chooses one of three shapes. • Consequently, the compiled version of the program, i.e., the bytecode that executes on the Java Virtual Machine, does not specify which draw(...) method is appropriate. • The choice of the correct draw(...) method is postponed until the program executes; that is, the choice is postponed until runtime. • Polymorphism via dynamic or late binding refers to choosing the appropriate method not at compile time, but at runtime. • When the TestDraw application runs, Java determines which form of draw(...) to execute.
How Dynamic Binding Works • The reference variable shape is declared to be of type Shape: Shape shape • Shape is the apparent type or declared type of shape. • A Shape object cannot be instantiated because Shape is an abstract class. • The variable shape can refer to a Square object or a Triangle object, or an object of any concrete class that extends Shape.
How Dynamic Binding Works • The real type or actual type of a reference variable is the type of the object that is created by the new operation. • The real type of shape is Square, RightTriangle, or Triangle, depending on user input. • Assume that the user, TestDraw, chooses to draw a right triangle. • In this case, the real type of shape is RightTriangle. • When the draw(...) method is invoked by shape, Java begins searching for a fully implemented draw(...) method. • The search begins in the RightTriangle class (the real type of shape). • If the RightTriangle class has implemented a draw(...) method then the search ends, and that method is called. • If not, then Java searches the parent of RightTriangle. • Searching continues all the way up the hierarchy until an implemented draw(...) method is found (or until the Object class is reached). • Java uses late binding for all method invocations except final, private, and static methods.
Polymorphism Makes Programs Extensible • Polymorphism allows you to generalize your classes with ease. Problem Statement: • Expand the Shape class with a subclass, EmptySquare, that implements a draw method, which produces a square that is not filled. ****** * * * * ******
Polymorphism Makes Programs Extensible Java Solution: • class EmptySquare extends Shape • { • public EmptySquare() • { • super(); // calls default Shape constructor • } • public EmptySquare(int x, char ch) • { • super(x,ch); // call 2-argument Shape constructor • } • public void draw(int x, int y) • { • // move down y lines • for ( int i = 1; i <= y; i++) • System.out.println(); • // for each row • for (int len = 1; len<= rows; len++) • { • // indent x spaces • for (int i = 1; i <= x; i++) • System.out.print(' '); • // print a character on an edge • // print spaces in the interior • for(int j = 1; j <=rows; j++) • if (j ==1|| j==rows || len==rows || len == 1 ) // on edge • System.out.print(character); • else • System.out.print(" "); • System.out.println(); • } • } • }