Computer Science 15-110, Spring 2010
Class Notes:  Getting Started with Writing Classes


In class this week we started to write our own classes.

The first class we are writing is a simple Fraction class.  We would like the following code to work:

  // We want this, but can't have it (darn!)
  public static void main(String[] args) {
    Fraction f1 = 2/3;
    Fraction f2 = 3/9;
    Fraction f3 = f1*f2;
    System.out.println(f1);
    System.out.println(f2);
    System.out.println(f3);
  }

Unfortunately, we cannot overload the / and * operators highlighted above to work this way (you can in some other languages, but not in Java).

So instead we'll settle on this version, which is similar but written in a way that we actually can support:

  // Compare this to the version above
  public static void main(String[] args) {
    Fraction f1 = new Fraction(2,3);
    Fraction f2 = new Fraction(3,9);
    Fraction f3 = f1.times(f2);
    System.out.println(f1);
    System.out.println(f2);
    System.out.println(f3);
  }

And here is the code we wrote in class (warts and all) to do it:

class FractionDemo {
  public static void main(String[] args) {
    Fraction f1 = new Fraction(2,3);
    Fraction f2 = new Fraction(3,9);
    Fraction f3 = f1.times(f2);
    System.out.println(f1.toString()); // 2/3
    System.out.println(f2); // 1/3
    System.out.println(f3); // 2/9
    System.out.println(f3+".getNum()=" + f3.getNum());
    System.out.println(f3+".getDen()=" + f3.getDen());

    System.out.println("Now you can 'safely' set the num");
    System.out.println("and it will still be reduced:");    
    f3.setNum(9);
    System.out.println(f3);

    System.out.println("But the fact that Fraction is now");
    System.out.println("mutable leads to this ugliness...");
    Fraction f4 = new Fraction(2,3);
    Fraction f5 = f4;
    f5.setNum(5);
    System.out.println(f4);
    System.out.println(f5);
    System.out.println("Conclusion:  it was a bad idea to");
    System.out.println("make Fractions mutable");
  }
}
class Fraction {

  // instance variables (the data for each instance)
  private int num, den;

  // Constructor
  // First store the paramters in the instance variables
  // Then reduce the fraction.
  public Fraction(int num, int den) {
    this.num = num;
    this.den = den;
    reduce();
  }

  // reduce helper method
  // Called by the constructor and also by the mutators ("setters").
  private void reduce() {
    if (this.den == 0) return;
    int gcd = gcd(this.num, this.den);
    this.num /= gcd;
    this.den /= gcd;
  }

  // gcd helper method
  // This is static because it does not refer to any instance variables.
  public static int gcd(int x, int y) {
    // gcd(x,y) == gcd(y,x%y)
    while (y != 0) {
      int r = x%y;
      x = y;
      y = r;
    }
    return x;
  }

  // accessors ("getters")
  public int getNum() { return this.num; }
  public int getDen() { return this.den; }

  // mutators ("setters")
  // bad idea for Fraction class, but included here
  // for demonstrational purposes.
  public void setNum(int num) {
    this.num = num;
    reduce();
  }

  // toString instance method
  // Convert the instance variables into a String.
  public String toString() {
    if (den == 1)
      return "" + this.num;
    return this.num + "/" + this.den;
  }

  // times instance method
  // Multiply "this" Fraction by "that" Fraction and return the result
  // as a new Fraction.
  public Fraction times(Fraction that) {
    int numerator = this.num * that.num;
    int denominator = this.den * that.den;
    Fraction result = new Fraction(numerator, denominator);
    return result;
  }
}

carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem