Arrays, Recursion, and Complexity Lesson 9—Classes Continued Lesson 9 — Classes Continued Solutions Answers to Review Questions Exercise 9.1 1. Java allocates a separate set of memory cells in each instance for the instance variables of a class. By contrast, only one set of cells is allocated for the class variables. 2. First, a static method can be included to allow the user to call the method by sending a message to the class. This method can serve as a public accessor or mutator of a class variable. Second, a static method can be included to perform some useful calculation. The Math class methods are good examples. Third, a static method can be included in a set of cooperating helper methods to decompose responsibilities for tasks in a class. 3. The reference to instVar in the static method is a syntax error because static methods cannot reference instance variables. 4. A public constant is accessible to all clients, and a static constant is accessible by using the class name as a reference. Exercise 9.2 1. A Java interface specifies the set of public methods for classes that implement that interface. It serves as a form of glue that holds the parts of a software system together. 2. Some classes are so simple that they do not need interfaces; moreover, an interface is commonly used when there is more than one implementing class. Exercise 9.3 1. public interface StudentSpecs { public public public public public public public void setName (String nm); String getName (); void setScore (int i, int score); int getScore (int i); int getAverage(); int getHighScore(); String toString(); } 2. The expression implements <an interface> causes the compiler to check the implementing class for the presence of all the methods in the specified interface. If any of them are missing, a syntax error occurs. 1 Arrays, Recursion, and Complexity Lesson 9—Classes Continued Exercise 9.4 1. A class hierarchy is a set of classes that is organized by the relationship of subclass and superclass. An example is the hierarchy Object/Circle/Wheel, where Circle is a subclass of Object and Wheel is a subclass of Circle. 2. The expression extends <a class> is used to inherit the data and behavior of another class. 3. To run a constructor of the same form in the superclass, one uses the form super(<parameters>) at the beginning of the corresponding constructor in the subclass. 4. With methods other than constructors, one uses the form super.<method name> (<parameters>). 5. The visibility modifier protected allows subclasses in a hierarchy to access instance and class variables or methods of superclasses without allowing other clients in the system to access these items. 6. There is a syntax error. The method setSpokes is not included in the Shape interface. The programmer attempts to send this message to an instance of Wheel, but this object is masquerading as a Shape. The variable s must be cast to a Wheel before sending it the setSpokes message. Exercise 9.5 1. An abstract class serves as a repository of data and behavior common to a set of subclasses. Because this class is abstract, it cannot be instantiated. An example is the AbstractShape class, which is abstract and defines the behavior common to circles and rectangles. 2. We declare abstract methods for two possible reasons. First, the abstract class in which they are declared implements an interface, but the implementation of these methods is deferred to the concrete classes. Second, even if there is no interface, these methods must be implemented in all subclasses, so declaring them abstract enforces this. 3. A final method cannot be overridden in a subclass. Examples are the accessors for variables that are defined in an abstract class. These methods should not be overridden by subclasses. 4. Here is a diagram of the Pen class hierarchy: AbstractPen Exercise 9.6 StandardPen RainbowPen BackwardPen WigglePen WiggleRainbowPen 2 Arrays, Recursion, and Complexity Lesson 9—Classes Continued 1. Generally, to locate the right method to execute, the JVM first looks in the class of the receiver object. If the method is not found there, the JVM looks at this class's superclass, if there is one. This process is repeated until a method is found or an exception is thrown (if the method is not eventually found in the Object class). In this example, the server's method someMethod is executed first. Within this method, the JVM executes a call to the method someMethod in the superclass. Exercise 9.7 1. The rule for passing a parameter object is the same as the rule for assignment, namely, the class of the actual parameter must be the same as or less inclusive than the class of the formal parameter. Exercise 9.8 1. /* * Precondition: 1 <= i <= 3 * Returns: the score at position i if the preconditions are satisfied * or 0 otherwise */ public int getScore(int i) Exercise 9.9 1. /* * Precondition: 1 <= i <= 3 * throws IllegalArgumentException if i < 1 or i > 3 * Returns: the score at position i if the preconditions are satisfied * or 0 otherwise */ public int getScore(int i){ if (i < 1 || i > 3) throw new IllegalArgumentException("i must be >= 1 and <= 3"); return scores[i – 1] } Exercise 9.10 1. The programmer should use equals instead of == when comparing two objects because == is too restrictive. In cases where two distinct objects are structurally the same (have the same values for all their instance variables), == would return false because == returns true only when the operands refer to one object. 2. true false false 3. When an object is assigned to a variable, that variable contains a reference to the object. 4. To obtain a true copy of an object, you must create a new instance of that object's class and then copy the original object's instance variables to the new object's variables. REVIEW QUESTIONS 3 Arrays, Recursion, and Complexity Lesson 9—Classes Continued Vocabulary Review Abstract class: A class that defines attributes and methods for subclasses but is never instantiated. Abstract method: A method that is specified but not implemented in an abstract class. The subclasses must implement this method. Class (static) method: A method that is invoked when a message is sent to a class. For example, Math.sqrt is a class method. Class (static) variable: A variable that is visible to all instances of a class and, if public, is accessed by specifying the class name. Concrete class: A class that can be instantiated. Final method: A method that cannot be implemented by a subclass. Inheritance: The process by which a subclass can reuse attributes and behavior defined in a superclass. Interface: A Java file that simply specifies the methods to be implemented by another class. A class that implements several interfaces can thus adopt the behavior of several classes. Overriding: The process of re-implementing a method already implemented in a superclass. Postcondition: A statement of what is true after a certain action is taken. Precondition: A statement of what is true before a certain action is taken. Fill in the Blank 1. Methods and variables that belong to a class rather than an instance are called class or static variables and methods. 2. The keyword used to invoke a constructor or method in a superclass is called super. 3. The visibility modifier protected makes a method or variable visible to subclasses but not to other clients. 4. A(n) abstract class contains common behavior and data for a set of subclasses but is not instantiated. 5. A(n) abstract method consists of just a head and forces all subclasses to implement it. 6. Preconditions and postconditions state the assumptions that are true before a method executes correctly and after it executes correctly. 7. The method equals is the conventional Java method for comparing two objects for equality, whereas the method clone is the conventional Java method for copying an object. Solutions to Projects 4 Arrays, Recursion, and Complexity Lesson 9—Classes Continued Project 9-3 // Solution to Project 9.3 import TurtleGraphics.Pen; // Notice the use of the word "abstract" in the class header. // This class implements the Shape interface. // We don't need to say that the class extends Object as that is the default. abstract public class AbstractShape implements Shape { // Here we declare variables common to all subclasses. protected double xPos; protected double yPos; // Even though this class is never instantiated, it needs constructors // to initialize its variables. public AbstractShape (){ xPos = 0; yPos = 0; } public AbstractShape (double xLoc, double yLoc){ xPos = xLoc; yPos = yLoc; } // There is no code for the next two methods; therefore, they are abstract // and terminate with a semicolon. All subclasses must define these methods. abstract public double area(); abstract public void draw (Pen p); // These next three methods will never be changed in a subclass; therefore, // they are declared final, meaning they cannot be overridden. public final double getXPos(){ return xPos; } public final double getYPos(){ 5 Arrays, Recursion, and Complexity Lesson 9—Classes Continued return yPos; } public final void move (double xLoc, double yLoc){ xPos = xLoc; yPos = yLoc; } // Another abstract method to be defined in subclasses. abstract public void stretchBy (double factor); abstract public double perimeter(); // Subclasses will override this method. // Notice that the method calls area(). More will be said about // this later. public String toString(){ String str = "(X,Y) Position: (" + xPos + "," + yPos + ")\n" + "Area: " + area(); return str; } } // Solution to Project 9.3 import TurtleGraphics.Pen; // This class extends AbstractShape and in the process implements // the Shape interface. public class Circle extends AbstractShape { protected double radius; public Circle() { super(); // Activate a constructor in AbstractShape. radius = 1; // Then initialize radius. } public Circle (double xLoc, double yLoc, double r) { super (xLoc, yLoc); // Activate a constructor in AbstractShape. radius = r; // Then initialize radius. } 6 Arrays, Recursion, and Complexity Lesson 9—Classes Continued // The next three methods were abstract in the superclass. // Now we define them. public double area() { return Math.PI * radius * radius; } public double perimeter(){ return Math.PI * radius * 2; } public void draw (Pen p) { double side = 2.0 * Math.PI * radius / 120.0; p.up(); p.move (xPos + radius, yPos - side / 2.0); p.setDirection (90); p.down(); for (int i = 0; i < 120; i++){ p.move (side); p.turn (3); } } public void stretchBy (double factor) { radius *= factor; } // Notice that the toString method calls the corresponding method in the // superclass in order to accomplish its task. // In the superclass, the toString method calls area, which will activate // the area method in this class and not the area method in the superclass. public String toString() { String str = "CIRCLE\n" + "Radius: " + radius + "\n" + super.toString(); return str; } } // Solution to Project 9.3 // No additional comments are needed in this class. All the important // points have already been made. 7 Arrays, Recursion, and Complexity Lesson 9—Classes Continued import TurtleGraphics.Pen; public class Rect extends AbstractShape { private double height, width; public Rect() { super(); height = 1; width = 1; } public Rect (double xLoc, double yLoc, double h, double w) { super (xLoc, yLoc); height = h; width = w; } public double area() { return height * width; } public double perimeter(){ return height * 2 + width * 2; } public void draw (Pen p) { p.up(); p.move (xPos, yPos); p.down(); p.setDirection (0); p.move (width); p.turn (-90); p.move (height); p.turn (-90); p.move (width); p.turn (-90); p.move (height); } public void stretchBy (double factor) { height *= factor; width *= factor; } public String toString() { String str = "RECTANGLE\n" + "Width & Height: " + width + " & " + height +"\n" + super.toString(); return str; 8 Arrays, Recursion, and Complexity Lesson 9—Classes Continued } } // Solution to Project 9.3 import TurtleGraphics.Pen; public interface Shape { public double area(); public double perimeter(); public void draw (Pen p); public double getXPos(); public double getYPos(); public void move (double xLoc, double yLoc); public void stretchBy (double factor); public String toString(); } // Solution to Project 9.3 public class TestShapes { public static void main (String[] args) { // Instantiate a circle, a wheel, and a rectangle Shape s1 = new Circle (20, 20, 20); Shape s2 = new Wheel (20, 20, 20, 6); Shape s3 = new Rect(20, 20, 10, 10); System.out.println("Perimeter of circle: " + s1.perimeter() + "\n" + "Perimeter of wheel: " + s2.perimeter() + "\n" + "Perimeter of rectangle: " + s3.perimeter()); } } import TurtleGraphics.Pen; public class Wheel extends Circle { private int spokes; // The number of spokes in the wheel // xPos, yPos, and radius are inherited from Circle public Wheel() { super(); // Activate the constructor Circle() to // initialize xPos, yPos, and radius. 9 Arrays, Recursion, and Complexity spokes = 0; Lesson 9—Classes Continued // Now initialize spokes. } public Wheel (double xLoc, double yLoc, double r, int s) { super (xLoc, yLoc, r); // Activate the constructor // Circle (double xLoc, double yLoc, double r) // to initialize xPos, yPos, and radius. spokes = s; // Now initialize spokes. } public void draw (Pen p) { // Draw the wheel's rim by calling the draw method in the superclass. super.draw (p); // Draw the spokes for (int i = 1; i <= spokes; i++){ p.up(); p.move (xPos, yPos); p.setDirection (i * 360.0 / spokes); p.down(); p.move (radius); } } public void setSpokes (int s) { spokes = s; } public String toString() { String str = "WHEEL\n" + "Radius: " + radius + "\n" + "Spokes: " + spokes + "\n" + "(X,Y) Position: (" + xPos + "," + yPos + ")\n" + "Area: " + area(); return str; } } Project 9-4 // Solution to Project 9.4 import TurtleGraphics.Pen; // Notice the use of the word "abstract" in the class header. // This class implements the Shape interface. 10 Arrays, Recursion, and Complexity Lesson 9—Classes Continued // We don't need to say that the class extends Object as that is the default. abstract public class AbstractShape implements Shape { // Here we declare variables common to all subclasses. protected double xPos; protected double yPos; // Even though this class is never instantiated, it needs constructors // to initialize its variables. public AbstractShape (){ xPos = 0; yPos = 0; } public AbstractShape (double xLoc, double yLoc){ xPos = xLoc; yPos = yLoc; } // There is no code for the next two methods; therefore, they are abstract // and terminate with a semicolon. All subclasses must define these methods. abstract public double area(); abstract public void draw (Pen p); // These next three methods will never be changed in a subclass; therefore, // they are declared final, meaning they cannot be overridden. public final double getXPos(){ return xPos; } public final double getYPos(){ return yPos; } public void move (double xLoc, double yLoc){ // We must override this method in class Triangle, so it can no longer // be final. xPos = xLoc; 11 Arrays, Recursion, and Complexity Lesson 9—Classes Continued yPos = yLoc; } // Two more abstract methods to be defined in subclasses. abstract public double perimeter(); abstract public void stretchBy (double factor); // Subclasses will override this method. // Notice that the method calls area(). More will be said about // this later. public String toString(){ String str = "(X,Y) Position: (" + xPos + "," + yPos + ")\n" + "Area: " + area(); return str; } } // Solution to Project 9.4 import TurtleGraphics.Pen; // This class extends AbstractShape and in the process implements // the Shape interface. public class Circle extends AbstractShape { protected double radius; public Circle() { super(); // Activate a constructor in AbstractShape. radius = 1; // Then initialize radius. } public Circle (double xLoc, double yLoc, double r) { super (xLoc, yLoc); // Activate a constructor in AbstractShape. radius = r; // Then initialize radius. } // The next three methods were abstract in the superclass. // Now we define them. public double area() { 12 Arrays, Recursion, and Complexity Lesson 9—Classes Continued return Math.PI * radius * radius; } public void draw (Pen p) { double side = 2.0 * Math.PI * radius / 120.0; p.up(); p.move (xPos + radius, yPos - side / 2.0); p.setDirection (90); p.down(); for (int i = 0; i < 120; i++){ p.move (side); p.turn (3); } } public double perimeter(){ return Math.PI * radius * 2; } public void stretchBy (double factor) { radius *= factor; } // Notice that the toString method calls the corresponding method in the // superclass in order to accomplish its task. // In the superclass, the toString method calls area, which will activate // the area method in this class and not the area method in the superclass. public String toString() { String str = "CIRCLE\n" + "Radius: " + radius + "\n" + super.toString(); return str; } } // Solution to Project 9.4 // No additional comments are needed in this class. All the important // points have already been made. import TurtleGraphics.Pen; public class Rect extends AbstractShape { 13 Arrays, Recursion, and Complexity Lesson 9—Classes Continued private double height, width; public Rect() { super(); height = 1; width = 1; } public Rect (double xLoc, double yLoc, double h, double w) { super (xLoc, yLoc); height = h; width = w; } public double area() { return height * width; } public void draw (Pen p) { p.up(); p.move (xPos, yPos); p.down(); p.setDirection (0); p.move (width); p.turn (-90); p.move (height); p.turn (-90); p.move (width); p.turn (-90); p.move (height); } public double perimeter(){ return height * 2 + width * 2; } public void stretchBy (double factor) { height *= factor; width *= factor; } public String toString() { String str = "RECTANGLE\n" + "Width & Height: " + width + " & " + height +"\n" + super.toString(); return str; } } // Solution to Project 9.4 14 Arrays, Recursion, and Complexity Lesson 9—Classes Continued import TurtleGraphics.Pen; public interface Shape { public double area(); public void draw (Pen p); public double getXPos(); public double getYPos(); public void move (double xLoc, double yLoc); public double perimeter(); public void stretchBy (double factor); public String toString(); } // Solution to Project 9.4 import TurtleGraphics.*; import java.awt.Color; public class TestShapes { public static void main (String[] args) { // Instantiate a pen and a shape Pen p = new StandardPen(); Shape s = new Triangle (0, 0, 50, 50, 100, 0); //new Wheel(0,0,100,5); //new Rect (0, 0, 50, 100); // Draw and print s.draw(p); System.out.println(s.area() + " " + s.perimeter()); System.out.println(s); // Move, strecth, draw, and print s.move(0, -100); s.stretchBy(0.5); s.draw(p); System.out.println(s.area() + " " + s.perimeter()); System.out.println(s); } } // Solution to Project 9.4 import TurtleGraphics.Pen; public class Triangle extends AbstractShape { 15 Arrays, Recursion, and Complexity Lesson 9—Classes Continued private double x2, x3, y2, y3; // The first vertex is (xPos, yPos) // The second vertex is (x2, y2) // The third vertex is (x3, y3). // Instantiate a default triangle with // vertices (0, 0), (20, 20), and (20, 0) public Triangle() { super(); x2 = 20; y2 = 20; x3 = 20; y3 = 0; } // Instantiate a triangle with // vertices (xx1, yy1), (xx2, yy2), (xx3, yy3) public Triangle (double xx1, double yy1, double xx2, double yy2, double xx3, double yy3) { super(xx1, yy1); this.x2 = xx2; this.y2 = yy2; this.x3 = xx3; this.y3 = yy3; } public double area() { double x1 = xPos, y1 = yPos; return 0.5 * Math.abs (x1*y2 - x2*y1 + x2*y3 - x3*y2 + x3*y1 - x1*y3); } public void draw (Pen p) { p.up(); p.move(xPos, yPos); p.down(); p.move(x2, y2); p.move(x3, y3); p.move(xPos, yPos); } public void move (double x, double y) { double deltaX = x - xPos; double deltaY = y - yPos; super.move(x, y); x2 += deltaX; 16 Arrays, Recursion, and Complexity Lesson 9—Classes Continued y2 += deltaY; x3 += deltaX; y3 += deltaY; } public double perimeter(){ double x1 = xPos, y1 = yPos; return Math.sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)) + // Side 1 Math.sqrt((x2 - x3)*(x2 - x3) + (y2 - y3)*(y2 - y3)) + // Side 2 Math.sqrt((x3 - x1)*(x3 - x1) + (y3 - y1)*(y3 - y1)); // Side 3 } public void stretchBy (double factor) { double x1 = xPos, y1 = yPos; x2 = x1 + (x2 - x1) * factor; y2 = y1 + (y2 - y1) * factor; x3 = x1 + (x3 - x1) * factor; y3 = y1 + (y3 - y1) * factor; } public String toString() { String str = "TRIANGLE\n" + "(x2,y2) : (" + x2 + "," + y2 + ")\n" + "(x3,y3) : (" + x3 + "," + y3 + ")\n" + super.toString(); return str; } } import TurtleGraphics.Pen; public class Wheel extends Circle { private int spokes; // The number of spokes in the wheel // xPos, yPos, and radius are inherited from Circle public Wheel() { super(); // Activate the constructor Circle() to // initialize xPos, yPos, and radius. spokes = 0; // Now initialize spokes. } public Wheel (double xLoc, double yLoc, double r, int s) { super (xLoc, yLoc, r); // Activate the constructor // Circle (double xLoc, double yLoc, double r) // to initialize xPos, yPos, and radius. 17 Arrays, Recursion, and Complexity spokes = s; Lesson 9—Classes Continued // Now initialize spokes. } public void draw (Pen p) { // Draw the wheel's rim by calling the draw method in the superclass. super.draw (p); // Draw the spokes for (int i = 1; i <= spokes; i++){ p.up(); p.move (xPos, yPos); p.setDirection (i * 360.0 / spokes); p.down(); p.move (radius); } } public void setSpokes (int s) { spokes = s; } public String toString() { String str = "WHEEL\n" + "Radius: " + radius + "\n" + "Spokes: " + spokes + "\n" + "(X,Y) Position: (" + xPos + "," + yPos + ")\n" + "Area: " + area(); return str; } } Project 9-5 // Solution to Project 9.5 abstract public class Employee { // Protected Instance Variables: protected String name; protected double rate; protected int hours; // Public Methods: public Employee(){ name = ""; rate = 0; 18 Arrays, Recursion, and Complexity Lesson 9—Classes Continued hours = 0; } public boolean setName(String nm){ if (nm.equals("")) return false; else{ name = nm; return true; } } public boolean setRate(double rt){ if (!(LOW_RATE <= rt && rt <= HIGH_RATE)) return false; else{ rate = rt; return true; } } public boolean setHours(int hrs){ if (!(LOW_HOURS <= hrs && hrs <= HIGH_HOURS)) return false; else{ hours = hrs; return true; } } public String getName(){ return name; } abstract public double getPay(); //--------------------------------------public static double TAX_RATE = 0.10; public static double LOW_RATE = 6.75; public static double HIGH_RATE = 30.50; public static double LOW_HOURS = 1; public static double HIGH_HOURS = 60; protected static double totalPay = 0; protected static double totalTax = 0; 19 Arrays, Recursion, and Complexity Lesson 9—Classes Continued public static String getNameRules() { return "nonblank"; } public static String getTypeRules() { return "1 or 2"; } public static String getRateRules() { return getRule (LOW_RATE, HIGH_RATE); } public static String getHoursRules() { return getRule (LOW_HOURS, HIGH_HOURS); } public static boolean typeOK (int type) { return type == 1 || type == 2; } public static double getTotalPay() { return totalPay; } public static double getTotalTax() { return totalTax; } private static String getRule (double low, double high) { return "between " + low + " and " + high + ", inclusive"; } } // Solution to Project 9.5 public class FullTimeEmployee extends Employee { public FullTimeEmployee(){ super(); } public double getPay() { double pay, tax; if (hours <= 40) 20 Arrays, Recursion, and Complexity Lesson 9—Classes Continued pay = rate * hours; else pay = rate * 40 + rate * 2 * (hours - 40); tax = pay * 0.10; pay = pay - tax; totalPay += pay; totalTax += tax; return pay; } } // Solution to Project 9.5 public class PartTimeEmployee extends Employee { public PartTimeEmployee() { super(); } public double getPay() { double pay, tax; pay = rate * hours; tax = pay * 0.10; pay = pay - tax; totalPay += pay; totalTax += tax; return pay; } } // Solution to Project 9.5 /* PayrollSystemInterface.java 1. Requrest employee name, type, pay rate, and hours. 2. Print employee name, taxes withheld, and pay. 3. Repeat until the name is blank. 4. Print the total taxes and pay. */ import TerminalIO.KeyboardReader; public class PayrollSystemInterface { public static void main (String [] args) { KeyboardReader reader = new KeyboardReader(); Employee emp; // employee String name; // name 21 Arrays, Recursion, and Complexity Lesson 9—Classes Continued int type; // type double rate; // hourly pay rate int hours; // hours worked String prompt; // user prompt; while (true){ // Get the name and break if blank System.out.println("Enter employee data"); name = reader.readLine(" Name (or blank to quit): "); name = name.trim(); // Trim off leading and trailing spaces if (name.length() == 0) break; // Get the type until valid while (true){ prompt = " Type (" + Employee.getTypeRules() + "): "; type = reader.readInt(prompt); if (Employee.typeOK(type)) break; } // Instantiate an employee of the correct type and set the name if (type == 1) emp = new FullTimeEmployee(); else emp = new PartTimeEmployee(); emp.setName(name); // Get the hourly pay rate until valid while (true){ prompt = " Hourly rate (" + Employee.getRateRules() + "): "; rate = reader.readDouble(prompt); if (emp.setRate(rate)) break; } // Get the hours worked until valid // To illustrate the possibilities we compress this code // into a single unreadable statement. while (!emp.setHours(reader.readInt (" Hours worked (" + Employee.getHoursRules() + "): "))); // Print the name and pay System.out.println (" The weekly pay for " + emp.getName() + " is $" + emp.getPay()); } // Print the total pay 22 Arrays, Recursion, and Complexity Lesson 9—Classes Continued System.out.println ("\nTotal taxes: " + Employee.getTotalTax()); System.out.println ("\nTotal pay : " + Employee.getTotalPay()); } } 23