/* Fraction.java */
import java.io.*;
/** The Fraction class implements nonnegative fractions (rational numbers).
*/
public class Fraction {
/* private fields within a Fraction. */
private static int numberOfFractions = 0;
private int numerator;
private int denominator;
/** Constructs a Fraction n/d.
* @param n is the numerator. Must be nonnegative.
* @param d is the denominator. Must be positive.
*/
public Fraction(int n, int d) {
if (n < 0) {
System.out.println("Fatal error: Negative numerator.");
System.exit(0);
}
if (d < 1) {
System.out.println("Fatal error: Nonpositive denominator.");
System.exit(0);
}
numberOfFractions++;
numerator = n;
denominator = d;
}
/** Constructs a Fraction n/1.
* @param n is the numerator. Must be nonnegative.
*/
public Fraction(int n) {
this(n, 1);
}
/** Constructs a Fraction 0/1.
*/
public Fraction() {
this(0, 1);
}
/** Copies the Fraction "original".
*/
public Fraction(Fraction original) {
this(original.numerator, original.denominator);
}
/** Converts this Fraction to a string format: "numerator/denominator."
* Fractions should be printed in reduced form (part of your assignment is
* to make this true).
* @return a String representation of this Fraction.
*/
public String toString() {
int thisGcd = gcd(numerator, denominator);
return (numerator / thisGcd + "/" + denominator / thisGcd);
}
/** Return the sum of two fractions.
* @param f2 is the Fraction to be added.
* @return the result of adding f2 to this Fraction.
*/
public Fraction add(Fraction f2) {
Fraction r = new Fraction((numerator * f2.denominator) + (f2.numerator * denominator), denominator * f2.denominator);
return r;
}
/** Replaces this Fraction's numerator with a new value.
* @param numerator is the new numerator. Must be nonnegative.
*/
public void changeNumerator(int numerator) { // DO NOT CHANGE THIS SIGNATURE!
// Fix the bug that prevents this method from working correctly.
if (numerator < 0) {
System.out.println("Fatal error: Negative numerator.");
System.exit(0);
}
this.numerator = numerator;
}
/** Returns the number of Fraction objects in existence.
* @return the number of Fraction objects in existence.
*/
public int fracs() { // DO NOT CHANGE THIS SIGNATURE!
// Fix the bug that prevents this method from working correctly.
return numberOfFractions;
}
/** Computes the greatest common divisor (gcd) of the two inputs.
* @param x must be nonnegative
* @param y must be nonnegative
* @return the gcd of x and y
*/
static private int gcd(int x, int y) {
/* Replace the following line with your solution. */
if(y == 0){
return x;
}else{
return gcd(y, x % y);
}
}
/** Put the Fraction class through some tests.
* @param argv is not used.
*/
public static void main(String[] argv) {
/* Test all four contructors and toString. */
Fraction f0 = new Fraction();
Fraction f1 = new Fraction(3);
Fraction f2 = new Fraction(12, 20);
Fraction f3 = new Fraction(f2);
System.out.println("\nTesting constructors and toString():");
System.out.println("The fraction f0 is " + f0.toString());
System.out.println("The fraction f1 is " + f1); // toString is implicit.
System.out.println("The fraction f2 is " + f2);
System.out.println("The fraction f3 is " + f3 + ", which should equal f2");
/* Test the add method. */
System.out.println("\nTesting add:");
Fraction sumOfTwo = f1.add(f2); // Sum of f1 and f2.
Fraction sumOfThree = f0.add(f1.add(f2)); // Sum of f0, f1, and f2.
System.out.println("The sum of " + f1 + " and " + f2 + " is " + sumOfTwo);
System.out.println("The sum of " + f0 + ", " + f1 + " and " + f2 + " is " + sumOfThree);
/* Test the methods used in Part III. */
System.out.println("\nTesting changeNumerator and fracs:");
f3.changeNumerator(7);
System.out.println("Now f3 is " + f3 + ", which should be 7/20");
System.out.println("The total number of Fraction objects is " + f3.fracs());
/* Test gcd function (static method). */
System.out.println("\nTesting gcd:");
System.out.println("The gcd of 2 and 10 is: " + gcd(2, 10));
System.out.println("The gcd of 15 and 5 is: " + gcd(15, 5));
System.out.println("The gcd of 24 and 18 is: " + gcd(24, 18));
System.out.println("The gcd of 10 and 10 is: " + gcd(10, 10));
System.out.println("The gcd of 21 and 400 is: " + gcd(21, 400));
}
}
(1) this
if the parameters or local variables of a method have the same name as the fields of an object, then the former have priority, and the “this” keyword is needed to refer to the object’s fields.
“this” is a keyword in Java, which normally refers to the object on which a method is invoked. In a constructor, it can be used (as
below) to invoke a constructor from within another constructor.
public class Fraction {
/* private fields within a Fraction. */
private static int numberOfFractions = 0;
private int numerator;
private int denominator;
/** Constructs a Fraction n/d.
* @param n is the numerator. Must be nonnegative.
* @param d is the denominator. Must be positive.
*/
public Fraction(int n, int d) {
if (n < 0) {
System.out.println("Fatal error: Negative numerator.");
System.exit(0);
}
if (d < 1) {
System.out.println("Fatal error: Nonpositive denominator.");
System.exit(0);
}
numberOfFractions++;
numerator = n;
denominator = d;
}
/** Constructs a Fraction n/1.
* @param n is the numerator. Must be nonnegative.
*/
public Fraction(int n) {
this(n, 1);
}
/** Constructs a Fraction 0/1.
*/
public Fraction() {
this(0, 1);
}
/** Copies the Fraction "original".
*/
public Fraction(Fraction original) {
this(original.numerator, original.denominator);
}
}
a good software engineering: reusing code!
reduced duplicate code, the program is shorter, and more importantly, if we later find a bug in the constructor, we might only need to fix the first constructor to fix all of them.
(2) toString
any object can have a toString method, and if it does, that method will be automatically called when you concatenate the object to a String. (Actually, every object has a toString method, but the default toString isn’t particularly enlightening.)
System.out.println("The fraction f0 is " + f0.toString());
System.out.println("The fraction f1 is " + f1); // toString is implicit.
如果我们想让一个类以我们希望的方式转化成String类型,就必须重写toString()方法。
public String toString() {
int thisGcd = gcd(numerator, denominator);
return (numerator / thisGcd + "/" + denominator / thisGcd);
}
(3) greatest common divisor - recursive GCD function
/** Computes the greatest common divisor (gcd) of the two inputs.
* @param x must be nonnegative
* @param y must be nonnegative
* @return the gcd of x and y
*/
static private int gcd(int x, int y) {
/* Replace the following line with your solution. */
if(y == 0){
return x;
}else{
return gcd(y, x % y);
}
}
(4) reduced form
public String toString() {
int thisGcd = gcd(numerator, denominator);
return (numerator / thisGcd + "/" + denominator / thisGcd);
}