java programming: from the ground up chapter 13: polymorphism

Post on 04-Jan-2016

225 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

• The code segment overloads the constructor of a Song class.

• The constructor is polymorphic; the constructor has three forms.

1. public class Song2. {3. private String composer;4. private String lyricist;5.6. public Song () // default constructor7. {8. composer ="" ;9. lyricist = "";10. }11. public Song(String name) // same person wrote words and music12. {13. composer =name ;14. lyricist = name;15. }16. public Song (String name1, String name2) // two songwriters17. {18. composer =name1;19. lyricist = name2;20. }21. // other Song methods go here.......22. }

• 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:

******************** *****Square

%%%%%%%%%% %%%%%RightTriangle

# # # # # # # # # # # # # # #

Triangle

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:

1. public abstract class Shape 2. {3. protected int rows; // figure drawn on rows rows4. protected char character; // the drawing character5.  6. public Shape()7. {8. rows = 0;9. char character = ' ';10. }11.  12. public Shape(int x, char ch)13. {14. rows = x;15. character = ch;16. }17.  18. public int getRows()19. {20. return rows;21. }22.  23. public char getCharacter()24. {25. return character;26. }27.  28. public void setRows(int y)29. {30. rows = y;31. }32.  33. public void setCharacter(char ch)34. {35. character = ch;36. }37.  38. public abstract void draw(int x, int y); // must be implemented in concrete subclasses39.  40. }

The Shape Hierarchy

public class Square extends Shape{public Square(){ // call Shape default constructor super(); }public Square(int x, char ch){ // call Shape 2 argument constr. super(x,ch);} 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(' '); for(int j = 1; j <=rows; j++) System.out.print(character); System.out.println(); } }}

public class RightTriangle extends Shape{public RightTriangle(){ // call Shape default constructor super();}public RightTriangle(int x, char ch){ // call Shape 2 argument constr.

super(x,ch);}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(' '); for (int j = 1; j <= len; j++) System.out.print(character); System.out.println(); } }}

public class Triangle extends Shape{public Triangle (){ // call Shape default constructor super();}public Triangle (int x, char ch){ // call Shape 2 argument constr.

super(x,ch);}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; the vertex is centered for(int i=0; i <= rows-len+x; i++) System.out.print(" "); for(int i =1; i<=len; i++) System.out.print(character +" " ); System.out.println(); } }}

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:

• The main(...) 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

1. import java.util.*;2. public class TestDraw3. {4. public static void main(String[] args)5. {6. Scanner input = new Scanner(System.in);7. Shape shape = null; // all references can be upcast to Shape8. int shapeNumber; //code number for each type of figure9. System.out.print("Enter 1: Square, 2: RightTriangle, 3: Equilateral Triangle: ");10. shapeNumber = input.nextInt();11.  12. switch (shapeNumber)13. {14. case 1 : shape = new Square(4,'*'); //size 4, draw with *15. break;16. case 2 : shape = new RightTriangle(5,'#'); //size 5, draw with #17. break;18. case 3 : shape = new Triangle(6,'+'); //size 6, draw with +19. break;20. default : System.out.println("Invalid entry"); // shapeNumber is not 1,2, or 321. System.exit(0); // bad data, terminate the application22. }23. shape.draw(1,1);24. }25. }

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: 1. class EmptySquare extends Shape2. {3. public EmptySquare()4. {5. super(); // calls default Shape constructor 6. }7.  8. public EmptySquare(int x, char ch)9. {10. super(x,ch); // call 2-argument Shape constructor11. }12.  13. public void draw(int x, int y)14. {15. // move down y lines16. for ( int i = 1; i <= y; i++)17. System.out.println();

18. // for each row 19. for (int len = 1; len<= rows; len++)20. {21. // indent x spaces22. for (int i = 1; i <= x; i++)23. System.out.print(' ');24.  25. // print a character on an edge26. // print spaces in the interior27.  28. for(int j = 1; j <=rows; j++)29. if (j ==1|| j==rows || len==rows || len == 1 ) // on edge30. System.out.print(character);31. else32. System.out.print(" ");33. System.out.println();34. }35. }36. }

Polymorphism and the Object class

• Most horror films have tag lines – catchphrases such as “Frankenstein: A Monster Science Created - But Could Not Destroy!”

Problem Statement:

• Design an application that stores Movie objects (a film title and a tag line) in an array, andallows Holly to search the array and retrieve a film’s tag line, given the title of the film.

 Java Solution:

• In addition to the two attributes, title and tagLine, the following Movie class:

– implements the standard getter and setter methods,

– overrides the toString() method inherited from Object so that the toString() version of the Movie class returns the title and the tag line as a String,

– overrides the equals(...) method inherited from Object implementing an equality that is based on the title of a film, so that two Movie objects with the same title are equal, and

– implements the Comparable interface by alphabetically comparing titles so that the array of Movie objects can be sorted by title.

Polymorphism and the Object class

Movie overrides equals(Object o) and toString(); Movie implements Comparable

Polymorphism and the Object class

1. public class Movie implements Comparable2. {3. private String title;4. private String tagLine;5.  6. public Movie()7. // default constructor, makes an empty Movie object8. {9. title = "";10. tagLine = "";11. }12.  13. public Movie( String name, String tag)14. {15. // two-argument constructor, creates a Movie object with a title and tag line16. title = name;17. tagLine = tag;18. }19.  20. public boolean equals(Object o)21. // override the equals object inherited from Object22. // two Movie objects are equal if they have the same title23. {24. return title.equals(((Movie)o).title); //notice that o must be cast to Movie25. }26.  27. public int compareTo(Object o)28. // implement compareTo from the Comparable interface29. // compareTo compares two titles. The compareTo from String is invoked30. {31. return title.compareTo(((Movie)o).title); // compares two Strings32. }33.  34.

35. public String toString()36. // overwrites toString() from Object37. {38. return "Title: "+title+" Tag line: "+ tagLine;39. }40.  41. public void setTitle(String title)42. {43. this.title = title;44. }45.  46. public String getTitle()47. {48. return title;49. }50.  51. public void setTagLine(String tagLine)52. {53. this. tagLine = tagLine;54. }55.  56. public String getTagLine ()57. {58. return tagLine;59. }60. }

Polymorphism and the Object class

• To locate a particular movie, the application utilizes the binary search algorithm.

• Binary search utilizes a sorted array.

• Because Movie implements the Comparable interface, an array of Movie references can be ordered.

• In the implementation of binary search e, the array parameter x and the key parameter are both declared of type Object.

• Thus, the method call,

search(Object[] x, Object key)

can pass arguments of any class.

Polymorphism and the Object class

1. public class Search2. {3. public static int search(Object [] x, Object key, int size)4. {5. // binary search from Chapter 76. int lo = 0;7. int hi = size -1;8. int mid = (lo+hi)/2;9. while ( lo <= hi)10. {11. if (key.equals(x[mid])) // key found12. return mid;13. else if (((Comparable)key).compareTo(x[mid]) < 0) 14. hi = mid -1;15. else16. lo = mid + 1;17. mid = (lo+hi)/2;18. }19. return -1; // key not found20. }21. }

• The cast on line 13: 

else if (((Comparable)key).compareTo(x[mid]) < 0)

is necessary because the parameter key refers to an Object, and Object does not implement Comparable.

• Without the downcast, the compiler issues a message to the effect that the name compareTo is unknown.

Polymorphism and the Object class

1. import java.util.Scanner;2. import java.io.*;3.  4. public class MovieSearch5. {6. Scanner input = new Scanner(System.in);7. private String title, tagLine;8. private Movie[] movies ;9. private final int MAX_MOVIES = 500;10. private int num; // the total number of films in the file

11. public MovieSearch() throws IOException12. {13. num = 0;14. movies = new Movie[MAX_MOVIES];15. File inputFile = new File("movielines.txt");16. if( !inputFile.exists())17. {18. System.out.println("File movielines.txt not found ");19. System.exit(0);20. }21. Scanner input = new Scanner(inputFile);22. String line; // to hold one full line from the file23. while (input.hasNext()) // while there is more data24. {25. String name = input.nextLine(); // advance to next line, returns all “skipped”

data26. String tag = input.nextLine();27. movies[num] = new Movie (name, tag);28. num++;29. }30.  31. input.close();32. SelectionSort.sort(movies, num); // the array must be kept sorted to utilize binary search33. System.out.println("\n"+ num +" titles entered");34. System.out.println("-------------------\n");35. searchFilm();36. }

37. public void searchFilm()38. {39. // Prompt user for a movie title40. // Search the array for the film with that title41. // If the film is in the array, print the title and tagline42. // If the film is not in the array, issue a message

43. System.out.println();44. Movie key = new Movie(); // an empty Movie object45. int place; // a position in the array46. System.out.println("Input a title. Hit Enter to end");47. do48. { //get title from user49. System.out.print("\nTitle: ");50. title = input.nextLine();51. if (title.equals(""))52. break; // end if user hits 'Enter'53. key.setTitle(title); // wrap title in a Movie object54. key.setTagLine(""); //the tagline is empty at this point55.  56. // invoke binary search to find a movie object with the title as key57. // if successful, place contains the position in the array; otherwise58. // place contains -159. place = Search.search(movies, key, num); // key is a Movie object60.  61. if (place >= 0 && place < num) // successful search62. System.out.println(movies[place]); // print the object at place63. else64. System.out.println(title +" not found");65. } while(true);66. }67.  68. public static void main(String[] args) throws IOException69. {70. MovieSearch movieSearch = new MovieSearch();71. }72. }

The Movie Class

Discussion

The Movie Class:

• On line 21 of the Movie class

return title.equals(((Movie)x).title); 

the equals(...) method invoked on line 21 is called by title, which is a String.

• The String class overrides equals(Object). So the call

title.equals(((Movie)x).title); 

compares two String objects via String's version of equals(...), i.e., by comparing the characters in each String.

• The cast of x to Movie is necessary because the apparent type of x is Object and Objects do not have title attributes.

• Similarly, the statement

return title.compareTo(((Movie)x).title);

invokes the compareTo(...) method of the String class.

• The remainder of the Movie class is straightforward and should present no difficulty.

The Search Class

The Search Class:

• On line 11 of the Search class,   if (key.equals(x[mid]))

the key object is compared to x[mid] via equals(...).

• This is the equals(...) method inherited from Object.

• If this equals(...) method is not overridden in Movie, then references are compared, and the result is incorrect.

• Similarly, on line 13,

else if (((Comparable)key).compareTo(x[mid]) < 0)

the compareTo(...) method is invoked by key.

• Accordingly, Movie implements the Comparable interface.

The MovieSearch Class

The MovieSearch Class:

• The statements on lines 22-28 continually perform the following actions:

– read a title and tagline from the text file, movielines.txt,

– instantiate a Movie object with the two-argument constructor, and

– store a reference to the Movie object in the array movies,

until all data has been read from movielines.txt.

The MovieSearch Class

• The searchFilm() method repeatedly

– creates an empty Movie object, key (line 42),

– queries a user for the title of a movie,

– sets the title attribute of key appropriately and sets the tagline field to the empty string

– passes key to search(...), which returns the index of key in the array movies, and

– processes the returned information from search(...):

• If key is not found, search(...) returns –1.

• If key is found, the film and tagline are displayed, otherwise a “title not found” message is issued.

until a user presses “Enter” without supplying a movie title.

top related