«^»
8.4. Using the class Shape and its subclasses

The following program uses the classes Shape, Circle and Rectangle. It reads some data describing some shapes from a file called data. The file could contain the values: 4, 2, 100, 200, 30, 50, 1, 150, 200, 30, 2, 200, 200, 50, 80, 1, 250, 200 and 40 (where each value is on a separate line of the file). This data is meant to be interpreted as follows: there are four shapes; the first one is a rectangle with an x-coordinate of 100, a y-coordinate of 200, a width of 30, a height of 50; the second shape is a circle with an x-coordinate of 150, a y-coordinate of 200, a radius of 30; and so on.

0639: import java.io.BufferedReader;                          // FileToScreen.java
0640: import java.io.FileReader;
0641: import java.io.IOException;
0642: public class FileToScreen {
0643:    public static void main(String[ ] args) throws IOException {
0644:       BufferedReader input = 
0645:             new BufferedReader(new FileReader("data"));
0646:       String line = input.readLine();
0647:       int numShapes = Integer.parseInt(line);
0648:       Shape[] shapes = new Shape[numShapes];
0649:       for (int shapeNumber = 0; shapeNumber<numShapes; shapeNumber++) {
0650:          line = input.readLine();  int shape = Integer.parseInt(line);
0651:          line = input.readLine();  int x = Integer.parseInt(line);
0652:          line = input.readLine();  int y = Integer.parseInt(line);
0653:          switch ( shape ) {
0654:             case 1:
0655:                line = input.readLine();
0656:                int radius = Integer.parseInt(line);
0657:                shapes[shapeNumber] = new Circle(radius, x, y); 
0658:                break;
0659:             case 2:
0660:                line = input.readLine();
0661:                int width = Integer.parseInt(line);
0662:                line = input.readLine();
0663:                int height = Integer.parseInt(line);
0664:                shapes[shapeNumber] = new Rectangle(width, height, x, y);
0665:                break;
0666:          }
0667:       }
0668:       for (int shapeNumber = 0; shapeNumber<numShapes; shapeNumber++) {
0669:          Shape tShape = shapes[shapeNumber];
0670:          tShape.translate(1, 2);
0671:          System.out.println(tShape);
0672:       }
0673:    }
0674: }

The program stores the details about the shapes in an array called shapes:

0648:       Shape[] shapes = new Shape[numShapes];
and uses the following two statements to put values into the array:
0657:                shapes[shapeNumber] = new Circle(radius, x, y); 
0664:                shapes[shapeNumber] = new Rectangle(width, height, x, y);
So the program does not use the array to store any references to objects of the class Shape: instead, each element is either a reference to a Circle object or a reference to a Rectangle object.

At the end of the program, there is a for statement whose aim is to output the details about the shapes that have been stored. It repeatedly executes the following three statements:

0669:          Shape tShape = shapes[shapeNumber];
0670:          tShape.translate(1, 2);
0671:          System.out.println(tShape);
In the first of these, the variable tShape is made to refer to either a Circle object or a Rectangle object. Then the translate method is applied to the object. Because neither Circle nor Rectangle declare a translate method, it will be the translate method of the superclass (Shape) that will be used. Finally, the println statement will use either Circle's or Rectangle's toString method in order to print the shape referred to by tShape. This is another example of dynamic binding.

When the program is executed with the above data, this for statement produces the following output:

101:202:30:50
151:202:30
201:202:50:80
251:202:40