Java Programming From the Ground Up Chapter 13

  • Slides: 30
Download presentation
Java Programming: From the Ground Up Chapter 13: Polymorphism

Java Programming: From the Ground Up Chapter 13: Polymorphism

Polymorphism • Polymorphism is the third fundamental concept of OOP. • In contrast to

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

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 Song 2. { 3. private String composer; 4. private String lyricist; 5. 6. public Song () // default constructor 7. { 8. composer ="" ; 9. lyricist = ""; 10. } 11. public Song(String name) // same person wrote words and music 12. { 13. composer =name ; 14. lyricist = name; 15. } 16. public Song (String name 1, String name 2) // two songwriters 17. { 18. composer =name 1; 19. lyricist = name 2; 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

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 Hound. Dog(); elvis = new Beagle(); elvis = new Bassett(); • Because a Hound. Dog is-a Dog, a Hound. Dog 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 Hound. Dog object, a Beagle object, or a Bassett object.

Dynamic (or Late) Binding • A third form of polymorphism, dynamic or late binding,

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

The Shape Hierarchy • Each class of the Shape hierarchy encapsulates a different geometrical shape. • Some typical shapes are: ***** ***** Square % %% %%%%% Right. Triangle # # # # Triangle

The Shape Hierarchy Problem Statement: • Design classes Square, Right. Triangle, and Triangle that

The Shape Hierarchy Problem Statement: • Design classes Square, Right. Triangle, 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 – character, the keyboard character used for drawing the figure.

The Shape Hierarchy Java Solution: • There is much the same about the three

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, Right. Triangle, and Triangle.

The Shape Hierarchy The Shape hierarchy

The Shape Hierarchy The Shape hierarchy

The Shape Hierarchy • The abstract class Shape has the following form: 1. 2.

The Shape Hierarchy • The abstract class Shape has the following form: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. public abstract class Shape { protected int rows; // figure drawn on rows protected character; // the drawing character public Shape() { rows = 0; character = ' '; } public Shape(int x, char ch) { rows = x; character = ch; } public int get. Rows() { return rows; } public char get. Character() { return character; } public void set. Rows(int y) { rows = y; } public void set. Character(char ch) { character = ch; } public abstract void draw(int x, int y); // must be implemented in concrete subclasses }

The Shape Hierarchy public class Square extends Shape { public Square() { // call

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 Right. Triangle extends Shape { public Right. Triangle() { // call Shape default constructor super(); } public Right. Triangle(int x, char ch) { // call Shape 2 argument constr. 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(); 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(); } } } // 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

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 Right. Triangle is-a Shape, and a Triangle is-a Shape, all references are upcast to Shape

The Shape Hierarchy 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.

The Shape Hierarchy 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. import java. util. *; public class Test. Draw { public static void main(String[] args) { Scanner input = new Scanner(System. in); Shape shape = null; // all references can be upcast to Shape int shape. Number; //code number for each type of figure System. out. print("Enter 1: Square, 2: Right. Triangle, 3: Equilateral Triangle: "); shape. Number = input. next. Int(); switch (shape. Number) { case 1 : shape = new Square(4, '*'); //size 4, draw with * break; case 2 : shape = new Right. Triangle(5, '#'); //size 5, draw with # break; case 3 : shape = new Triangle(6, '+'); //size 6, draw with + break; default : System. out. println("Invalid entry"); // shape. Number 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

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 Right. Triangle object (line 15), or a Triangle object (line 17).

The Shape Hierarchy • When Test. Draw is compiled and translated into bytecode, the

The Shape Hierarchy • When Test. Draw 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 Test. Draw application runs, Java determines which form of draw(. . . ) to execute.

How Dynamic Binding Works • The reference variable shape is declared to be of

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

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, Right. Triangle, or Triangle, depending on user input. • Assume that the user, Test. Draw, chooses to draw a right triangle. • In this case, the real type of shape is Right. Triangle. • When the draw(. . . ) method is invoked by shape, Java begins searching for a fully implemented draw(. . . ) method. • The search begins in the Right. Triangle class (the real type of shape). • If the Right. Triangle class has implemented a draw(. . . ) method then the search ends, and that method is called. • If not, then Java searches the parent of Right. Triangle. • 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.

Polymorphism Makes Programs Extensible • Polymorphism allows you to generalize your classes with ease. Problem Statement: • Expand the Shape class with a subclass, Empty. Square, that implements a draw method, which produces a square that is not filled. ***** * * * *****

Polymorphism Makes Programs Extensible Java Solution: 1. 2. 3. 4. 5. 6. 7. 8.

Polymorphism Makes Programs Extensible Java Solution: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. class Empty. Square extends Shape { public Empty. Square() { super(); // calls default Shape constructor } public Empty. Square(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(); 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. // 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 == 1 ) // on edge System. out. print(character); else System. out. print(" "); System. out. println(); } } }

Polymorphism and the Object class • Most horror films have tag lines – catchphrases

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, and allows 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 tag. Line, the following Movie class: – implements the standard getter and setter methods, – overrides the to. String() method inherited from Object so that the to. String() 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 to. String(); Movie implements

Polymorphism and the Object class Movie overrides equals(Object o) and to. String(); Movie implements Comparable

Polymorphism and the Object class 1. 2. 3. 4. 5. 6. 7. 8. 9.

Polymorphism and the Object class 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. public class Movie implements Comparable { private String title; private String tag. Line; public Movie() // default constructor, makes an empty Movie object { title = ""; tag. Line = ""; } public Movie( String name, String tag) { // two-argument constructor, creates a Movie object with a title and tag line title = name; tag. Line = tag; } public boolean equals(Object o) // override the equals object inherited from Object // two Movie objects are equal if they have the same title { return title. equals(((Movie)o). title); //notice that o must be cast to Movie } public int compare. To(Object o) // implement compare. To from the Comparable interface // compare. To compares two titles. The compare. To from String is invoked { return title. compare. To(((Movie)o). title); // compares two Strings } 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. public String to. String() // overwrites to. String() from Object { return "Title: "+title+" Tag line: "+ tag. Line; } public void set. Title(String title) { this. title = title; } public String get. Title() { return title; } public void set. Tag. Line(String tag. Line) { this. tag. Line = tag. Line; } public String get. Tag. Line () { return tag. Line; } }

Polymorphism and the Object class • To locate a particular movie, the application utilizes

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. 2. 3. 4. 5. 6. 7. 8. 9.

Polymorphism and the Object class 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. public class Search { public static int search(Object [] x, Object key, int size) { // binary search from Chapter 7 int lo = 0; int hi = size -1; int mid = (lo+hi)/2; while ( lo <= hi) { if (key. equals(x[mid])) // key found return mid; else if (((Comparable)key). compare. To(x[mid]) < 0) hi = mid -1; else lo = mid + 1; mid = (lo+hi)/2; } return -1; // key not found } } • The cast on line 13: else if (((Comparable)key). compare. To(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 compare. To is unknown.

Polymorphism and the Object class 1. 2. 3. 4. 5. 6. 7. 8. 9.

Polymorphism and the Object class 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. import java. util. Scanner; import java. io. *; public class Movie. Search { Scanner input = new Scanner(System. in); private String title, tag. Line; private Movie[] movies ; private final int MAX_MOVIES = 500; private int num; // the total number of films in the file 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. public Movie. Search() throws IOException { num = 0; movies = new Movie[MAX_MOVIES]; File input. File = new File("movielines. txt"); if( !input. File. exists()) { System. out. println("File movielines. txt not found "); System. exit(0); } Scanner input = new Scanner(input. File); String line; // to hold one full line from the file while (input. has. Next()) // while there is more data { String name = input. next. Line(); // advance to next line, returns all “skipped” data String tag = input. next. Line(); movies[num] = new Movie (name, tag); num++; } input. close(); Selection. Sort. sort(movies, num); // the array must be kept sorted to utilize binary search System. out. println("n"+ num +" titles entered"); System. out. println("----------n"); search. Film(); } 37. 38. 39. 40. 41. 42. public void search. Film() { // Prompt user for a movie title // Search the array for the film with that title // If the film is in the array, print the title and tagline // If the film is not in the array, issue a message 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. System. out. println(); Movie key = new Movie(); // an empty Movie object int place; // a position in the array System. out. println("Input a title. Hit Enter to end"); do { //get title from user System. out. print("n. Title: "); title = input. next. Line(); if (title. equals("")) break; // end if user hits 'Enter' key. set. Title(title); // wrap title in a Movie object key. set. Tag. Line(""); //the tagline is empty at this point // invoke binary search to find a movie object with the title as key // if successful, place contains the position in the array; otherwise // place contains -1 place = Search. search(movies, key, num); // key is a Movie object if (place >= 0 && place < num) // successful search System. out. println(movies[place]); // print the object at place else System. out. println(title +" not found"); } while(true); } public static void main(String[] args) throws IOException { Movie. Search movie. Search = new Movie. Search(); } }

The Movie Class Discussion The Movie Class: • On line 21 of the Movie

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. compare. To(((Movie)x). title); invokes the compare. To(.

• Similarly, the statement return title. compare. To(((Movie)x). title); invokes the compare. To(. . . ) method of the String class. • The remainder of the Movie class is straightforward and should present no difficulty.

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

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). compare. To(x[mid]) < 0) the compare. To(. . . ) method is invoked by key. • Accordingly, Movie implements the Comparable interface.

The Movie. Search Class: • The statements on lines 22 -28 continually perform the

The Movie. Search 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 Movie. Search Class • The search. Film() method repeatedly – creates an empty

The Movie. Search Class • The search. Film() 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.