Name CISC 3115 Modern Programming Techniques Spring 2018 Section TY3 Exam 2 Solutions 1. a. (25 points) A rational number is a number that can be represented by a pair of integers a numerator and a denominator. Write a class named Rational that represents rational numbers. The class should support the following state/behavior: A pair of integers, num and den, representing the numerator and denominator A constructor that accepts a pair of integer and uses them to initialize the instance variables. An exception should be thrown if the denominator is 0. A second constructor that accepts a single integer representing a whole number (i.e., with a denominator of 1). For full credit, you must invoke the two-parameter constructor (i.e., use this) A tostring method that returns the string representation num / den (e.g., 3/5), if the denominator is not equal to 1, and num (e.g., 7) otherwise. A Rational-returning method named multiply that accepts a Rational argument and returns a new Rational consisting of the product of the receiver and parameter (both Rationals). (The product of 2 rational numbers is a rational whose numerator is the product of the two numerators, and whose denominator is the product of the two denominators). A Rational-returning method named inverse that accepts no arguments and returns a new Rational representing the inverse (reciprocal) of its (Rational) parameter (i.e., the numerator becomes the new denominator and vice versa). An exception should be thrown if the inverse of 0 is attempted. A boolean-returning method named equals that that accepts a Rational argument and returns whether the receiver and parameter (both Rationals) are equal. (For the purpose of this question, assume two rational numbers are equal if their numerators and denominators are equal, i.e., assume 2/4 is not equal to 1/2). A main method that declares and creates two Rationals, using the two constructors, and illustrates the use of the multiply, inverse, and equals methods (one call to each is sufficient).
class Rational { Rational(int n, int d) throws Exception { if (d == 0) throw new Exception("0 denominator"); num = n; denom = d; Rational(int n) throws Exception {this(n, 1); public String tostring() { return denom!= 1? num + "/" + denom : num+""; Rational multiply(rational other) throws Exception { return new Rational(num * other.num, denom * other.denom); Rational inverse() throws Exception { if (num == 0) throw new Exception(""inverse of 0 attempted"); return new Rational(denom,num); boolean equals(rational other) { return num == other.num && denom == other.denom; int num, denom; public static void main(string [] args) throws Exception { Rational r1 = new Rational(3, 4), r2 = new Rational(12); System.out.println(r1 + " " + r2 + " "); System.out.println(r1.multiply(r2)); System.out.println(r1.inverse()); System.out.println(r1.equals(r1)); System.out.println(r1.equals(r2));
2. a. (10 points) Write an interface named Shape that specifies the following behavior: an int-returning method named perimeter, that returns the perimeter of a shape a double-returning method name area, that returns the area of a shape an int-returning method named numsides, that returns the number of sides of a shape. interface Shape { int perimeter(); double area(); int numsides(); b. (10 points) Write a class named Triangle that implements Shape with the following: three protected integer variables representing the three sides a constructor that accepts three integers and uses them to initialize the three sides of the triangle the method numsides the method perimeter an abstract method area abstract class Triangle implements Shape { Triangle(int s1, int s2, int s3) { side1 = s1; side2 = s2; side3 = s3; public int perimeter() {return side1 + side2 + side3; public abstract double area(); public int numsides() {return 3; int side1, side2, side3;
c. (10 points) Write a subclass of Triangle named EquilateralTriangle with the following: a constructor that accepts a single integer value representing the lengths of the sides the method area the area of an equilateral triangle is 3 4 s2, where s is the side. a tostring method that returns an equilateral triangle with side side, e.g. an equilateral triangle with side 10 class EquilateralTriangle extends Triangle { EquilateralTriangle(int s) {super(s, s, s); public double area() { return (Math.sqrt(3)/4)*(side1*size1); public String tostring() { return "an equilateral triangle with side " + side1;
d. (10 points) Suppose we wanted to add the following classes to our Shape hierarchy: IsocelesTriangle, RightTriangle, Rectangle, and Square. IsocelesTriangle and RightTriangle have the same set of methods as EquilateralTriangle, while Rectangle and Square provide all the methods of Shape plus an additional method named diagonal that returns the length of the diagonal. Draw what you think would be the OOPiest class hierarchy (i.e., the hierarchy which most exploits the benefits and of inheritance, polymorphism, etc). Explain your choices (in terms of the relationship between a subclass and superclass). In addition, for Rectangle and Square, please include which methods are implemented by which class. Shape Triangle IsocelesTriangle EquilateralTriangle RightTriangle Rectangle Square Triangle implements Shape IsocelesTriangle is a subclass of Triangle because an isosceles triangle is-a triangle EquilateralTriangle is a subclass of IsocelesTriangle because an equilateral triangle is-a isosceles triangle RightTriangle is a subclass of Triangle because a right triangle is-a triangle Rectangle implements Shape o Rectangle implements all the methods required by Shape Square is a subclass of Rectangle because a square is a rectangle; it inherits all the methods, possibly overriding tostring to provide a more customized value
3. Here is a program that assumes the Shape hierarchy of question 2 has been coded and is available (including the additional classes mentioned in part d of that question). class ShapeApp { public static void main(string [] args) { Shape [] shapes = new Shape[3]; shapes[0] = new EquilateralTriangle(3); shapes[1] = new RightTriangle(3, 4); shapes[2] = new Rectangle(3, 4); for (int i = 0; i < shapes.length; i++) { System.out.println(shapes[i].toString()); System.out.println(shapes[i].numSides()); System.out.println(shapes[i].perimeter()); System.out.println(shapes[i].area()); a. (15 points) What is the output of the above program? (use 1.7 for 3 ; also assume the tostring output for Rectangle is analogous to that of the tostring you coded for EquilateralTriangle). an equilateral triangle with side 3 3 9 3.82 (or anything in the neighborhood) a right triangle with sides 3 and 4(and hypoteneuse 5) 3 12 6.0 a rectangle with sides 3 and 4 4 14 12.0
b. (15 points) The loop of the program iterates through the array (once for each element, and thus a total of three times), each time calling the methods tostring, numsides, perimeter, and area. For each value of i, and each method, provide the name of the class whose method is being executed. For example, for i = 0, the tostring method called is the one in the EquilateralTriangle class. i = 0 i = 1 i = 2 Class tostring EquilateralTriangle RightTriangle Rectangle numsides Triangle Triangle Rectangle perimeter Triangle Triangle Rectangle area EquilateralTriangle RightTriangle Rectangle c. (5 points) Could we have made a call to diagonal (see part d of question 2) in the loop of the program? Explain your answer. The array is declared to have an element type of Shape. diagonal is not one of the methods specified in the Shape interface and thus would not be recognized by the compiler as one of the methods that may be invoked using an element of the array as the receiver.