Computer Science 15-100 (Sections T & U), Fall 2007
Class Notes:   Writing Classes (2 of 2)


Logistics

  1. Reading:  L&L Sections Chapter 4

We will start with our simple class (from last lecture):  Rational

(Note that the new state of our code from the end of class, demonstrating the concepts from today's lecture, is appended below.)

  1. Visibility Modifiers
    1. public:  visible to everyone
    2. protected:  only visible within the given package or within subclasses
    3. default:  only visible within the given package
    4. private:  only visible within the given class
       
  2. Instance Variables
    1. Non-static
    2. Require some object reference to access (hence, "instance" variables)
    3. Should be private (maybe default?)
    4. Can be initialized outside of a constructor
      1. Initialized before constructor is called
    5. Scope
      1. Visible from all instance methods (but not static methods!)
      2. Shadowing
      3. Using this.foo to escape shadowing
         
  3. Accessors and Mutators
    1. Accessor:  getFoo
    2. Mutator:   setFoo, clearFoo, incrementFoo, etc...
    3. For booleans:  isProperty, setProperty
       
  4. Constructors
    1. Default Constructor:  No args, get this for free unless you implement a constructor
    2. Invoking "super" constructor
    3. Invoking "this" constructor
       
  5. The toString method
    1. Every class gets a default toString method
    2. Can "override" this with your own
      1. Must have exactly this signature, visibility, and return type:
        public String toString()
         
  6. A Class's API (Application Programming Interface)
    1. All your public methods, and only your public methods
    2. What methods should be public in the Rational class?
       
  7. Encapsulation, Data Hiding, Self-Governing:
          Control access to, and changing of, object properties
    which is roughly equivalent to:
          Expose public interface without reference to private implementation

Here is our code at the end of class:

// This code was developed in class, so it does not have great style, etc...

public class RationalDemo {  
  public static void main(String[] args) {
    Rational r1 = new Rational(2,3);
    Rational r2 = new Rational(3,7);
    Rational r3 = r1.times(r2);
    Rational r4 = r2.times(r1);
    // r1.print();
    // r2.print();
    // r3.print();
    System.out.println(r1 + " * " + r2 + " = " + r3);
    System.out.println(r1 + " * " + r2 + " = " + r4);
    
    Rational r5 = new Rational();
    System.out.println(r5 + " * " + r2 + " = " + r5.times(r2));
    
    System.out.println(r1 + " / " + r2 + " = " + r1.dividedBy(r2));
  }
}

// This little class demonstrates some aspects of constructors
class Foo {
  public static void main(String[] args) {
    Foo f = new Foo();
    f.fooey();
    Foo g = new Foo(1);
    g.fooey();
  }

  // public Foo() { new Foo(10); } // This is a REALLY BAD IDEA 
  public Foo() { this(10); } // This is the RIGHT WAY to do this

  public Foo(int x) { this.x = x;}
  private int x;
  
  public void fooey() { System.out.println("Fooey: " + this.x); }
}

class Rational {
  public void print() {
    System.out.println("Hi, my value is " + this.toString());
  }
  
  public Rational reduce() {
    int newNum = this.num;
    int newDen = this.den;
    for (int f=Math.min(newNum,newDen); f>=2; f--)
      if ((newNum % f == 0) && (newDen % f == 0)) {
         newNum /= f;
         newDen /= f;
      }
    if (newNum == 0) newDen = 1;
    return new Rational(newNum,newDen);
  }
    
  public Rational times(Rational that) {
    int num = this.num * that.num;
    int den = this.den * that.den;
    Rational result = new Rational(num,den);
    return result.reduce();
  }

  // a/b + c/d = (ad/bd) + (bc/bd) = (ad + bc) / (bd)
  public Rational plus(Rational that) {
    // not yet implemented
    return null;
  }
  
  public Rational minus(Rational that) {
    // not yet implemented
    return null;
  }
  
  public Rational invert() {
    return new Rational(this.den,this.num).reduce();
  }
  
  //   a/b  /   c/d  == a/b * d/c
  public Rational dividedBy(Rational that) {
    return this.times(that.invert());
  }

  private int num = 5;  // silly, but demonstrates default values
  private int den;
  
  // accessors
  public int getNum() { return this.num; }
  public int getDen() { return this.den; }

  // mutators
  public void setNum(int num) { this.num = num; }
  public void setDen(int den) { this.den = den; }  
  public void setInteger(int i) { this.num = i; this.den = 1; }

  // constructors
  // public static Rational constructor(int num, int den) {
  public Rational(int num, int den) {
   this.num = num;
   this.den = den;
  }
  
  public Rational() {
    // call the other constructor providing default values
    //  for num and den
    this(0,1);
  }
    
  public String toString() {
    // return num + "/" + den;
    if (this.num == 0)
      // if we are 0, do not return a ratio
      return "0";
    else
      return this.num + "/" + this.den;
  }
}

Carpe diem!