Exercises

Included below are short-answer and programming exercises. Answers are provided for those exercises whose exercise number is a hyperlink. Because college faculty use these exercises in their exams, we have provided answers to roughly half of the exercises included here.


9.3 Consider the class Bicycle. Given your knowledge of some common components of bicycles, show a class hierarchy in which the class Bicycle inherits from other classes, which, in turn, inherit from yet other classes. Discuss the instantiation of various objects of class Bicycle. Discuss inheritance from class Bicycle for other closely related subclasses.

9.4 Define each of the following terms: single inheritance, multiple inheritance, interface, superclass and subclass.

9.5 Discuss why casting a superclass reference to a subclass reference is potentially dangerous.

9.6 Distinguish between single inheritance and multiple inheritance. Why does Java not support multiple inheritance? What feature of Java helps realize the benefits of multiple inheritance?

9.7 (True/False) A subclass is generally smaller than its superclass.

9.8 (True/False) A subclass object is also an object of that subclass’s superclass.

9.9 Some programmers prefer not to use protected access because it breaks information hiding in the superclass. Discuss the relative merits of using protected access vs. private access in superclasses.

9.10 Many programs written with inheritance could be solved with composition instead, and vice versa. Discuss the relative merits of these approaches in the context of the Point, Circle, Cylinder class hierarchy in this chapter. Rewrite the program of Fig. 9.10 (and the supporting classes) to use composition rather than inheritance. After you do this, reassess the relative merits of the two approaches both for the Point, Circle, Cylinder problem and for object-oriented programs in general.

9.11 Rewrite the Point, Circle, Cylinder program of Fig. 9.10 as a Point, Square, Cube program. Do this two ways–once with inheritance and once with composition.

9.12 In the chapter, we stated, "When a superclass method is inappropriate for a subclass, that method can be overridden in the subclass with an appropriate implementation." If this is done, does the subclass-is-a-superclass-object relationship still hold? Explain your answer.

9.13 Study the inheritance hierarchy of Fig. 9.2. For each class, indicate some common attributes and behaviors consistent with the hierarchy. Add some other classes (i.e., UndergraduateStudent, GraduateStudent, Freshman, Sophomore, Junior, Senior, etc.), to enrich the hierarchy.

9.14 Write an inheritance hierarchy for classes Quadrilateral, Trapezoid, Parallelogram, Rectangle and Square. Use Quadrilateral as the superclass of the hierarchy. Make the hierarchy as deep (i.e., as many levels) as possible. The private data of Quadrilateral should include the (x, y) coordinate pairs for the four endpoints of the Quadrilateral. Write a driver program that instantiates and displays objects of each of these classes. [In Chapter 11, "Graphics and Java2D," you will learn how to use Java’s drawing capabilities.]

9.15 Write down all the shapes you can think of–both two-dimensional and three-dimensional– and form those shapes into a shape hierarchy. Your hierarchy should have superclass Shape, from which class TwoDimensionalShape and class ThreeDimensionalShape are derived. Once you have developed the hierarchy, define each of the classes in the hierarchy. We will use this hierarchy in the exercises to process all shapes as objects of superclass Shape.

9.16 How is it that polymorphism enables you to program "in the general" rather than "in the specific"? Discuss the key advantages of programming "in the general."

9.17 Discuss the problems of programming with switch logic. Explain why polymorphism is an effective alternative to using switch logic.

9.18 Distinguish between inheriting interface and inheriting implementation. How do inheritance hierarchies designed for inheriting interface differ from those designed for inheriting implementation?

9.19 Distinguish between non-abstract methods and abstract methods.

9.20 (True/False) All methods in an abstract superclass must be declared abstract.

9.21 Suggest one or more levels of abstract superclasses for the Shape hierarchy discussed in the beginning of this chapter (the first level is Shape and the second level consists of the classes TwoDimensionalShape and ThreeDimensionalShape).

9.22 How does polymorphism promote extensibility?

9.23 You have been asked to develop a flight simulator that will have elaborate graphical outputs. Explain why polymorphic programming would be especially effective for a problem of this nature.

9.24 Develop a basic graphics package. Use the Shape class inheritance hierarchy from Fig. 9.3. Limit yourself to two-dimensional shapes such as squares, rectangles, triangles and circles. Interact with the user. Let the user specify the position, size, shape and fill colors to be used in drawing each shape. The user can specify many items of the same shape. As you create each shape, place a Shape reference to each new Shape object into an array. Each class has its own draw method. Write a polymorphic screen manager that walks through the array sending draw messages to each object in the array to form a screen image. Redraw the screen image each time the user specifies an additional shape. Investigate the methods of class Graphics to help draw each shape.

9.25 Modify the payroll system of Fig. 9.9 to add private instance variables birthDate (use class Date from Fig. 8.8) and departmentCode (an int) to class Employee. Assume this payroll is processed once per month. Then, as your program calculates the payroll for each Employee (polymorphically), add a $100.00 bonus to the person’s payroll amount if this is the month in which the Employee’s birthday occurs.

9.26 In Exercise 9.15, you developed a Shape class hierarchy and defined the classes in the hierarchy. Modify the hierarchy so that class Shape is an abstract superclass containing the interface to the hierarchy. Derive TwoDimensionalShape and ThreeDimensionalShape from class Shapethese classes should also be abstract. Use an abstract print method to output the type and dimensions of each class. Also include area and volume methods so these calculations can be performed for objects of each concrete class in the hierarchy. Write a driver program that tests the Shape class hierarchy.

9.27 Rewrite your solution to Exercise 9.26 to use a Shape interface instead of an abstract Shape class.

9.28 (Drawing Application) Modify the drawing program of Exercise 8.19 to create a drawing application that draws random lines, rectangles and ovals. [Note: Like an applet, a JFrame has a paint method that you can override to draw on the background of the JFrame.]

For this exercise, modify the MyLine, MyOval and MyRect classes of Exercise 8.19 to create the class hierarchy in Fig. 9.14.

Fig. 9.14

The MyShape hierarchy.

The classes of the MyShape hierarchy should be "smart" shape classes where objects of these classes know how to draw themselves (if provided with a Graphics object that tells them where to draw). The only switch or if/else logic in this program should be to determine the type of shape object to create (use random numbers to pick the shape type and the coordinates of each shape). Once an object from this hierarchy is created, it will be manipulated for the rest of its lifetime as a superclass MyShape reference.

Class MyShape in Fig. 9.14 must be abstract. The only data representing the coordinates of the shapes in the hierarchy should be defined in class MyShape. Lines, rectangles and ovals can all be drawn if you know two points in space. Lines require x1, y1, x2 and y2 coordinates. The drawLine method of the Graphics class will connect the two points supplied with a line. If you have the same four coordinate values (x1, y1, x2 and y2) for ovals and rectangles, you can calculate the four arguments needed to draw them. Each requires an upper-left x-coordinate value (minimum of the two x-coordinate values), an upper-left y-coordinate value (minimum of the two y coordinate values), a width (difference between the two x-coordinate values; must be nonnegative) and a height (difference between the two y-coordinate values; must be nonnegative). [Note: In Chapter 12, each x,y pair will be captured using mouse events from mouse interactions between the user and the program’s background. These coordinates will be stored in an appropriate shape object as selected by the user. As you begin the exercise, you will use random coordinate values as arguments to the constructor.]

In addition to the data for the hierarchy, class MyShape should define at least the following methods:

  1. A constructor with no arguments that sets the coordinates to 0.
  2. A constructor with arguments that sets the coordinates to the supplied values.
  3. Set methods for each individual piece of data that allow the programmer to independently set any piece of data for a shape in the hierarchy (e.g., if you have an instance variable x1, you should have a method setX1).
  4. Get methods for each individual piece of data that allow the programmer to independently retrieve any piece of data for a shape in the hierarchy (e.g., if you have an instance variable x1, you should have a method getX1).
  5. The abstract method
    public abstract void draw( Graphics g );
    This method will be called from the program’s paint method to draw a shape onto the screen.

The preceding methods are required. If you would like to provide more methods for flexibility, please do so. However, be sure that any method you define in this class is a method that would be used by all shapes in the hierarchy.

All data must be private to class MyShape in this exercise (this forces you to use proper encapsulation of the data and provide proper set/get methods to manipulate the data). You are not allowed to define new data that can be derived from existing information. As explained previously, the upper-left x, upper-left y, width and height needed to draw an oval or rectangle can be calculated if you already know two points in space. All subclasses of MyShape should provide two constructors that mimic those provided by class MyShape.

Objects of the MyOval and MyRect classes should not calculate their upper-left x-coordinate, upper-left y-coordinate, width and height until they are about to draw. Never modify the x1, y1, x2 and y2 coordinates of a MyOval or MyRect object to prepare to draw them. Instead, use the temporary results of the calculations described above. This will help us enhance the program in Chapter 12 by allowing the user to select each shape’s coordinates with the mouse.

There should be no MyLine, MyOval or MyRect references in the program–only MyShape references that refer to MyLine, MyOval and MyRect objects are allowed. The program should keep an array of MyShape references containing all shapes. The program’s paint method should walk through the array of MyShape references and draw every shape (i.e., call every shape’s draw method).

Begin by defining class MyShape, class MyLine and an application to test your classes. The application should have a MyShape instance variable that can refer to one MyLine object (created in the application’s constructor). The paint method (for your subclass of JFrame) should draw the shape with a statement like

currentShape.draw( g );

where currentShape is the MyShape reference and g is the Graphics object that the shape will use to draw itself on the background of the window.

Next, change the single MyShape reference into an array of MyShape references and hard code several MyLine objects into the program for drawing. The application’s paint method should walk through the array of shapes and draw every shape.

After the preceding part is working, you should define the MyOval and MyRect classes and add objects of these classes into the existing array. For now, all the shape objects should be created in the constructor for your subclass of JFrame. In Chapter 12, we will create the objects when the user chooses a shape and begins drawing it with the mouse.

9.29 In Exercise 9.28, you defined a MyShape hierarchy in which classes MyLine, MyOval and MyRect subclass MyShape directly. If the hierarchy was properly designed, you should be able to see the tremendous similarities between the MyOval and MyRect classes. Redesign and reimplement the code for the MyOval and MyRect classes to "factor out" the common features into the abstract class MyBoundedShape to produce the hierarchy in Fig. 9.15.

Fig. 9.15

The MyShape hierarchy.

Class MyBoundedShape should define two constructors that mimic the constructors of class MyShape and methods that calculate the upper-left x-coordinate, upper-left y-coordinate, width and height. No new data pertaining to the dimensions of the shapes should be defined in this class. Remember, the values needed to draw an oval or rectangle can be calculated from two (x,y) coordinates. If designed properly, the new MyOval and MyRect classes should each have two constructors and a draw method.

 


Selected Answers

Included below are answers to approximately half the of the exercises in the Cyber Classroom. We are not able to include answers to every exercise because college faculty use these exercises in their classroom exams.


 9.3 Consider the class Bicycle. Given your knowledge of some common components of bicycles, show a class hierarchy in which the class Bicycle inherits from other classes, which, in turn, inherit from yet other classes. Discuss the instantiation of various objects of class Bicycle. Discuss inheritance from class Bicycle for other closely related subclasses.
ANS: Possible classes are displayed in bold.
Bicycle
composed of:
Handle bars
Seat
Frame
Wheels
composed of:
Tires
Rims
Spokes
Pedals
Chain
composed of:
Links
Brakes
composed of:
Wires
Brake Pads
Brake Handles

9.4 Define each of the following terms: single inheritance, multiple inheritance, interface, superclass and subclass.
ANS:

9.5 Discuss why casting a superclass reference to a subclass reference is potentially dangerous.
ANS: The reference must refer to an object of the subclass, before being used. When the compiler looks at an object through a subclass reference, it expects to see all the pieces of the subclass. However, if the superclass reference orignally refered to a superclass object, the additional pieces added by the subclass do not exist. For this reason, an attempt to cast a subclass reference that refers to a subclass object into a superclass reference results in a ClassCastException at execution time.

9.6 Distinguish between single inheritance and multiple inheritance. Why does Java not support multiple inheritance? What feature of Java helps realize the benefits of multiple inheritance?
ANS: Single inheritance inherits from one class only. Multiple inheritance inherits from two or more classes. Java does not support multiple inheritance because of the problems that can be encountered with multiple inheritance. However, Java does support interfaces which provide the benefits of multiple inheritance without the potential problems.

9.7 (True/False) A subclass is generally smaller than its superclass.
ANS: False. A subclass is usually larger because it normally adds more data and more functionality.

9.8 (True/False) A subclass object is also an object of that subclass’s superclass.
ANS: True.

9.9 Some programmers prefer not to use protected access because it breaks information hiding in the superclass. Discuss the relative merits of using protected access vs. private access in superclasses.
ANS: Inherited private data is hidden in the subclass and is accessible only through the public or protected methods of the superclass. Using protected access enables the subclass to manipulate the protected members without using the access methods of the superclass. If the superclass members are private, the methods of the superclass must be used to access the data. This may result in a decrease in performance due to the extra method calls.

9.10

// Exercise 9.10 Solution
// Test.java
// Driver for point, circle, cylinder program
import javax.swing.*;

public class Test {
   public static void main( String args[] )
   {
      Cylinder cylinder = new Cylinder( 10, 3.3, 10, 10 ); 
      String result = "";

      result += cylinder.getCPointName() + ": " +
                    cylinder.getCPointString();
   
      result += "\n" + cylinder.getCircleName() + ": " + 
                    cylinder.getCircleString();
   
      result += "\n" + cylinder.getName() + ": " +
                    cylinder.toString();
  
      result += "\n" + cylinder.getCPointName() +
                    ": " + cylinder.getCPointString();

      result += "\n" + cylinder.getCircleName() +
                    ": " + cylinder.getCircleString();
      result += "\n" + "Area = " + cylinder.getCircleArea();

      result += "\n" + cylinder.getName() +
                    ": " + cylinder.toString();
      result += "\n" + "Area = " + cylinder.area();
      result += "\n" + "Volume = " + cylinder.volume();    
 
      JOptionPane.showMessageDialog( 
            null, result, "Shapes",
            JOptionPane.INFORMATION_MESSAGE );   
      System.exit( 0 );      
   }
}   

// Exercise 9.10 Solution
// Point.java
// Definition of class Point

public class Point {
   private double x, y; // coordinates of the Point

   public Point( double a, double b ) { setPoint( a, b ); }

   public void setPoint( double a, double b )
   {
      x = a;
      y = b;
   }

   public double getX() { return x; }

   public double getY() { return y; }

   public String toString() 
      { return "[" + x + ", " + y + "]"; }

   public String getName() { return "Point"; }
}

// Exercise 9.10 Solution
// Cylinder.java
// Definition of class Cylinder

public class Cylinder {
   private double height;  // height of Cylinder
   private Circle c;       // composition
    
   public Cylinder( double h, double r, double a, double b )      
   {
      c = new Circle( r, a, b ); 
      setHeight( h );
   }

   public void setHeight( double h )
      { height = ( h >= 0 ? h : 0 ); }
   
   public double getHeight() { return height; }

   public double area()
   {
      return 2 * c.area() + 2 * Math.PI * c.getRadius() * height;
   }
   
   public double volume() { return c.area() * height; }

   public String toString()
      { return c + "; Height = " + height; }

   public String getName() { return "Cylinder"; }

   public double getCircleArea() { return c.area(); }

   public String getCircleName() { return c.getName(); }

   public String getCircleString() { return c.toString(); }

   public String getCPointString() { return c.getPointString(); }

   public String getCPointName() { return c.getPointName(); }
}

// Exercise 9.10 Solution
// Circle.java
// Definition of class Circle

public class Circle {  
   private double radius;
   private Point p;       // composition 

   public Circle()  {  this( 0.0, 0.0, 0.0 );  }

   public Circle( double r, double a, double b )
   {
      p = new Point( a, b );   // instantiate point object     
      setRadius( r );  
   }

   public void setRadius( double r )
      { radius = ( r >= 0 ? r : 0 ); }

   public double getRadius() { return radius; }

   public double area() { return Math.PI * Math.pow( radius, 2 ); }

   public String toString()
      { return "Center = " + p + 
               "; Radius = " + radius; }

   public String getName() { return "Circle"; }

   public String getPointName() { return p.getName(); }

   public String getPointString() { return p.toString(); }
}

9.11

Inheritance

// Exercies 9.11 Solution
// Test.java
// Driver for point, square, cube hierarchy
import javax.swing.*;

public class Test {
   public static void main( String args[] )
   {
      Point point = new Point( 7, 11 );          
      Square square = new Square( 3.5, 22, 8 );  
      Cube cube = new Cube( 3.3, 10, 10 ); 

      Shape[] arrayOfShapes = new Shape[ 3 ];
      String result = "";

      arrayOfShapes[ 0 ] = point;
      arrayOfShapes[ 1 ] = square;
      arrayOfShapes[ 2 ] = cube;  
   
      result += point.getName() + ": " +
                    point.toString();
   
      result += "\n" + square.getName() + ": " + 
                    square.toString();
   
      result += "\n" + cube.getName() + ": " +
                    cube.toString();
      
      for ( int i = 0; i < 3; i++ ) {
         result += "\n" + arrayOfShapes[ i ].getName() +
            ": " + arrayOfShapes[ i ].toString();
          result += "\n" + "Area = " + 
            arrayOfShapes[ i ].area();
         result += "\n" + "Volume = " +
            arrayOfShapes[ i ].volume();
      }

      JOptionPane.showMessageDialog( 
            null, result, "Shapes",
            JOptionPane.INFORMATION_MESSAGE );   
      System.exit( 0 );  
   }
}   
   
// Exercies 9.11 part B solution
// Point.java
// Definition of class Point

public class Point extends Shape {
   protected double x, y; 
  
   public Point( double a, double b ) { setPoint( a, b ); }

   public void setPoint( double a, double b )
   {
      x = a;
      y = b;
   }
 
   public double getX() { return x; }

   public double getY() { return y; }

   public String toString() 
      { return "[" + x + ", " + y + "]"; }
 
   public String getName() { return "Point"; }
}

// Exercies 9.11 part B solution
// Square.java
// Definition of class Square

public class Square extends Point {  
   protected double side;

   public Square()
      { this( 0.0, 0.0, 0.0 ); }
  
   public Square( double s, double a, double b )
   {
      super( a, b );  
      setSide( s );  
   }

   public void setSide( double s )
      { side = ( s >= 0 ? s : 0 ); }

   public double getSide() { return side; }
  
   public double area() { return Math.pow( side, 2 ); }

   public String toString()
      { return "Corner = " + super.toString() + 
               "; side = " + side; }

   public String getName() { return "Square"; }
}

// Exercies 9.11 part B solution
// Cube.java
// Definition of class Cylinder

public class Cube extends Square {
   private double depth;

   public Cube( double s, double a, double b )      
   {
      super( s, a, b );
      depth = s;
   }
   
   public double area() { return super.area() * 6; }
   
   public double volume() { return super.area() * depth; }
  
   public String toString()
      { return super.toString() + "; depth = " + depth; }

   public String getName() { return "Cube"; }
}

// Exercies 9.11 part B solution
// Shape.java
// Definition of abstract base class Shape

public abstract class Shape {
   public double area() { return 0.0; }
   public double volume() { return 0.0; }
   public abstract String getName();   
}

Composition

// Exercise 9.11 Solution
// Test.java
// Driver for point, square, cube composition program
import javax.swing.*;

public class Test {
   public static void main( String args[] )
   { 
      Cube cube = new Cube( 3.3, 10, 10 );
      String result = "";
   
      result += cube.getSPointName() + ": " +
                    cube.getSPointString();
   
      result += "\n" + cube.getSquareName() + ": " + 
                    cube.getSquareString();
   
      result += "\n" + cube.getName() + ": " +
                    cube.toString();
  
      result += "\n" + cube.getSPointName() +
                    ": " + cube.getSPointString();

      result += "\n" + cube.getSquareName() +
                    ": " + cube.getSquareString();
      result += "\n" + "Area = " + cube.getSquareArea();

      result += "\n" + cube.getName() +
                    ": " + cube.toString();
      result += "\n" + "Area = " + cube.area();
      result += "\n" + "Volume = " + cube.volume();            

      JOptionPane.showMessageDialog( 
            null, result, "Shapes",
            JOptionPane.INFORMATION_MESSAGE );   
      System.exit( 0 );  
   }
}   

// Exercies 9.11 part A solution
// Point.java
// Definition of class Point

public class Point {
   private double x, y; // coordinates of the Point

   public Point( double a, double b ) { setPoint( a, b ); }

   public void setPoint( double a, double b )
   {
      x = a;
      y = b;
   }

   public double getX() { return x; }

   public double getY() { return y; }

   public String toString() 
      { return "[" + x + ", " + y + "]"; }

   public String getName() { return "Point"; }
}

// Exercies 9.11 part A solution
// Square.java
// Definition of class Square

public class Square {  
   private double side;
   private Point p;       // composition 

   public Square()  {  this( 0.0, 0.0, 0.0 );  }

   public Square( double s, double a, double b )
   {
      p = new Point( a, b );   // instantiate point object     
      setSide( s );  
   }

   public void setSide( double s )
      { side = ( s >= 0 ? s : 0 ); }

   public double getSide() { return side; }
   
   public double area() { return Math.pow( side, 2 ); }

   public String toString()
      { return "Corner = " + p.toString() + 
               "; Side = " + side; }
  
   public String getName() { return "Square"; }

   public String getPointName() { return p.getName(); }

   public String getPointString() { return p.toString(); }
}

// Exercies 9.11 part A solution
// Cube.java
// Definition of class Cube

public class Cube {
   private double depth;  
   private Square s;       // composition
    
   public Cube( double m, double a, double b )      
   {
      s = new Square( m, a, b ); 
      depth = m;
   }
      
   public double getDepth() { return depth; }
   
   public double area() { return s.area() * 6; } 
     
   public double volume() { return s.area() * depth; }

   public String toString()
      { return s.toString() + "; Depth = " + depth; }
   
   public String getName() { return "Cube"; }
 
   public double getSquareArea() { return s.area(); }

   public String getSquareName() { return s.getName(); }
  
   public String getSquareString() { return s.toString(); }
 
   public String getSPointString() { return s.getPointString(); }

   public String getSPointName() { return s.getPointName(); }
}

9.12 In the chapter, we stated, "When a superclass method is inappropriate for a subclass, that method can be overridden in the subclass with an appropriate implementation." If this is done, does the subclass-is-a-superclass-object relationship still hold? Explain your answer.
ANS: Yes, the subclass-is-a-superclass-object relationship still holds. In Java, it is not possible to break this relationship.

9.17 Discuss the problems of programming with switch logic. Explain why polymorphism is an effective alternative to using switch logic.
ANS: The main problem with programming using the switch structure is the extensibility and maintainability of the program. A program containing many switch structures is difficult to modify. All the structures must be modified to handle the processing of an additional type or of one less type. Polymorphism determines the type of an object automatically, so it is not necessary to determine the type of an object to process the object in a generic manner.

9.19 Distinguish between non-abstract methods and abstract methods.
ANS: A non-abstract method provides implementation. An abstract method does not provide any implementation. Subclasses of the abstract class containing the abstract methods provide implementation for abstract methods by overriding them. If a subclass does not override an abstract method, the subclass becomes an abstract class as well.

9.20 (True/False) All methods in an abstract superclass must be declared abstract.
ANS: False. An abstract class must have at least one abstract method. Any number of methods in the class can be non-abstract.