Program 5

Writing Classes

Introduction to Computer Science I
ICS-21


Introduction This programming assignment is designed to ensure that you know how to write simple classes: both classes filled with static methods (referenced by the class name) and "normal" classes (from which one can construct objects storing state in instance variables and call their methods on these objects). Primarily, you will be writing methods (either static or not) and write a few constructors and specify/use a few fields (mostly instance variables). Of course, you will continue gaining experience with the standard control structures in Java (blocks, ifs, loops/breaks) as well as the more basic Java features (declarations and expression statements using arithmetic, state-change, relational and logical operators).

To write a class using iterative enhancement, we use the following process.

  1. Write a driver for testing the class, typically a console program that allows us to call every method in the class. I will often provide these; later we will examine writing a different kind of driver using JUnit.
  2. Decide on the needed instance variables for the class and declare (and if possible initialize) them.
  3. Write the required constructors.
  4. Write the header of each method, filled in with a minimal body. This is called stubbing methods in a class.
    • for a void method, the body can be just {}
    • for a method returning a reference type, the body should be {return null;}
    • for a method returning a primitive type, the body should just return some literal of that type (e.g., {return false;} or {return 0;} etc.)
  5. Once this class and its driver compiles, fill in the body of each method, then test it in the driver, then continue by filling in the body of the next method, etc. There is a bit of an art to determine which methods to implement/test first. A good heuristic is to implement/test toString first (to help debug the others), then implement/test the simplest methods first -the ones that do not call other methods defined in the class. Often (in the case of collection classes) the method for adding a value to a collection will have to be written early on, to test the accessors and the method to remove a value.

You will write three classes in this assignment. In all cases I will provide driver programs that you will use to test your classes. As always, you can check the behavior of your programs against mine by downloading, unzipping, and then running the file Program #5 Executables, to help you understand the specification of the problem and observe the programmer/user interaction that you are to implement. See Program #1 for details on how to run these executables on both PCs and in Eclipse (PCs and Macs). Remember, you can run these programs, but not examine their source (Java) code.

Note how packages are used in this assignment. In each package the driver program is complete, and you must write only one class that it drives: these classes are either empty or need to be revised. All other classes provided are complete. Please be careful when deciding whether variables are instance variables, parameter variables, or local variables, and using each of these.

To start working on this assignment, download Program #5 Project Folder which contains the outlines of classes you should write for this assignment and the driver programs that you should use to test these classes . Write, run, and debug each class/program. When you finish each part, submit its .java file.

Only one programmer of the pair should dropoff the programs: the same one for each part. It doesn't matter which of the pair submits, but that person should submit all the parts. Of course, each program should contain both student names (in the comment: the same one you cut, pasted, ane filled in at the top of each program in Program #1).


Static Library Write the methods in a class named SUM (abbreviating Static Utility Methods) that contains the four methods described below. The Driver class prompts the user for information to use when calling these methods and prints the results that they return (so you can more easily debug them).

First, change the SUM class to be in a different package: one using your UCI user ID (something like edu.uci.pattis) and use this package name when you import it into the Driver class. To do this, change the name of the package in the SUM class, then let Eclipse fix the problem (click the red X and select the first option: Move SUM.java to package (your package name)).

Please write the following methods to meet the specification stated. Throw no exceptions except for the ones mentioned below. As is normally the case, none of these methods do any input/output other than through parameters and returned values.

  1. majority takes three boolean parameters and returns a boolean result whose value is the one that is in the majority. majority(true,true,false) returns true. With three boolean arguments and only two possible boolean values, one values is always in the majority (either 2o f 3 or 3 of 3). Try to find a compact method body, NOT enumerating all eight possibilities. Run my executable for further information.

  2. isPrime takes one int parameter and returns a boolean whose value is true if the parameter is a prime number. If the parameter is negative, this method should throw an IllegalArgumentException with an appropriate message. Next is the defintion of "prime" we will use in this method's body. If the parameter is 0 or 1, it should return false (technically neither 0 nor 1 are prime); if the parameter is any larger value, it should return false if some number, between 2 and the parameter-1, exactly divides the parameter: for example, if the parameter is 15, try divisors between 2 and 14 (inclusive, using a general for loop. If any of thess values is a divisor, IMMEDIATELY return false; if none of these values exactly divides the parameter, then the method should finally return true. Run my executable for further information.

  3. constrain takes three int parameters and returns an int result whose value is constrained to lie within the 1st and 3rd parameter values. It returns the 2nd parameter, if it lies between the 1st and 3rd inclusive; it returns the 1st if the 2nd parameter is less than the 1st; it returns the 3rd if the 2nd parameter is greater than the 3rd. For example constrain(0,5,10) returns 5 because the value of the 2nd parameter is between the 1st and 3rd. But constrain(0,-5,10) returns 0 because the value of the 2nd parameter is smaller than the 1st parameter. And constrain(0,15,10) returns 10 because the value of the 2nd parameter is larger than the 3rd parameter. Run my executable for further information.

  4. digits takes one int parameter and returns an int result whose value is the number of digits in the first parameter. This method works for any parameter, and returns a positive value 1 or greater. For example digits(0) returns 1; digits(1245) returns 4; digits(-10) returns 2. This method computes its result by counting how many times it can divide the parameter by 10 before reaching a single digit number; each division represents "chopping off" a digit in the parameter. Run my executable for further information.

BigRational: Infinite Precision Rationals Write a class named BigRational by updating the class named Rational. This assignment is actually a bridge between using/writing classes, because you are actually just translating the Rational class into BigRational, which contains all same the methods, but with translated instance variables and bodies. In BigRational instead of using two int instance variables for storing the numerator and denominator (as Rational does), use two BigInteger instance variables, by importing and using the java.math.BigInteger class. In BigRational, these instance variables can store integers with any number of digits (tens, hundreds, thousands, etc.) Refer to the Javadoc of BigInteger throughout this assignment (you might even want to print a copy for quicker reference).

What you must do is translate the Rational class so that instead of using ints it becomes the BigRational class and uses BigInteger. Operators applied to int variables must be translated into method calls on BigInteger variables. Most operators on ints are available as equivalent methods on BigIntegers. Use the BigRational.java file provided; mostly it is a copy of the Rational.java file); you must translate all the Rational constructors and methods. The project file also contains a Driver class, which compiles correctly when the the BigRational class compiles correctly.

Here are some general hints for translation.

  • Wherever you see Rational or int in the class, change them to BigRational or BigInteger (except for the return type of the compareTo method, which should remain int, and the parameter to toDecimalString which should remain int).

  • The BigInteger class has static fields ZERO and ONE; if you need any other BigInteger values (say, 10) use a constructor to create one (e.g., BigInteger ten = new BigInteger("10");).

  • If int a,b,c; we write a + b * c but with BigInteger a,b,c; we write a.add( b.multiply(c) ); we can also write this expression as the cascaded method call b.multiply(c).add(a), although this looks a bit strange because the order of the operands has changed.

  • There is a gcd method in the BigInteger class (so you should use this method directly in the constructor: DO NOT define a private static method for this operation in the BigRational class; remove this method from your code).

  • When writing the compareTo method for BigRational make use of the the compareTo method for BigInteger (and remember, it should still return an int not a BigInteger).

  • Finally, I have already completely translated the toDecimalString method, which appears in both the original form and updated form (commented out). You can study the differences and use these methods as an guide to how to translate the other methods. Put the orignal code in comment (or remove it), and uncomment the translated code, which will work for BigInteger instance variables.
Run my executable for further information. After you program compiles and runs, intially test its methods by using the driver and entering small values that you can compute the result for (e.g., 1/2 + 1/3 = 5/6). Eventually try running the harmonic sum option with 100 or 200 for n and comparing its output to my executable. You DO NOT need to write/update the Javadoc for this class; just focus on translating the instance variables and methods.

Ball: For Bouncing Ball Simulations Write a simple class named Ball, which we can use to simulate a bouncing ball (there are two drivers for simulation: one textual -in the Ball class- and one graphical). We characterize a ball's state by five values; its
  • color (a Color which doesn't change)
  • size (an int (radius of ball in pixels) which doesn't change)
  • height (a double (feet) which changes during in the simulation)
  • elasticity (a double which doesn't change and determines how much the ball bounces)
  • velocity (a double (feet per second) which changes during in the simulation)
Here, some states are intrinsic ball properties independent of the simulation: its color, size, and elasticity (what percentage of its downward velocity is converted into upward velocity when it bounces); other states are a result of the simulation: its height and velocity.

Fill in the fields (instance variables), constructor, and methods in the Ball class.

  • The fields represent all the ball's states, using the types Color, int, and double.

  • The constructor's parameters specify all the ball's state, except the velocity, which should always start at 0. when new constructs a new Ball object.

  • The methods are mostly accessors that return information about the ball's state to the simulation so it can display a ball: getColor, getSize, getHeight. Note that the toString method should return a large String containing the name of ALL instance variables and their current values. It might return a values that prints like
    Ball[color=java.awt.Color[r=255,g=0,b=0],size=15,height=10.0,elasticity=0.9,velocity=0.0] Note that the Color class has its own toString method, which you can call.

  • The update method computes the new height and velocity of the ball after the specified amount of time passes. This is similar to the rocket calculation, but much simpler.
    • Compute the velocity at the end of the time interval: the velocity at the start of the time interval - gravity*dT.
    • Compute the average velocity over the interval: the average between the velocity at the start and end of the interval.
    • Compute the height at the end of the time interval: the height at the start of the time interval + the average velocity during the interval times dT.
    • If the height IS NOT negative, store the velocity at the end of the time interval into the velocity for the start of the next time interval; if the height IS negative, make it 0. and then store the opposite of the average velocity (times the elasticity) into the velocity for the start of the next time interval.
First test your Ball class using the main method in the Ball class itself; remember to rewrite the toString method correctly or it won't print anything; check your results against my executable.

Then test your Ball class using the graphic driver. For the colors, use only positive int values 0 to 255; for the size use a reasonable-sized positive integer (e.g., 15 pixels); for the height, don't exceed 10. for the elasticity, generally use a double value 0 to 1.; note that even with a perfect bounce (elasticity = 1.), because of the way the equations are simplified (not exact in terms of bouncing) some ball(s) may eventually come to rest and some not; try an elasticity > 1.

Actuallly, if you specify -1 for any value, a random number in the appropriate range will be use; the default values are -1 for everything except elasticity. Experiment by running the program with -1 and other values.

Note that I have written all the correct header methods inBall, so this part compiles correctly. Ball is the the only class that you must change, by filling in the instance variables, and bodies of the constructors and methods. Try debugging your ball using the Construct One button first, then test it later with Construct Many.