/* Basic Examples of Classes and Objects in Java, with exercise. These examples are intended to enforce your basic skills at using classes and objects. These are not advanced object oriented programming examples, except for the implmentation of the Comparable interface. When studying each of the following classes, first look at the test() function at the end of the class to get a sense of how the class SHOULD behave, then look at how the rest of the class is defined. Pay attention to: What instance variables are needed (these are the protected variables). What, if any variables and methods are static (and why). How the constructor is defined and how it relates to how objects are created. The difference between instance variables and the parameters and local variables of a function. The return type (or void) of each function. Also, pay attention to the difference between 'destructive' and non-destructive versions of functions. 'destructive' means the object is changed in place, while 'non-destructive' means the object the function is called on stays the same, but the function constructs and returns a new object. */ //// Example 1: NYC Metrocard class metrocard { protected double balance; // 0 by default protected static double fare = 2.75; // fare per ride - same for all cards. // constructor (with initial balance) public metrocard(double init) { balance = 0; refill(init); } public void refill(double amt) // add amt+bonus to balance (old formula) { if (amt<=0) return; double bonus = (int)(amt/(2*fare)) * 0.1*fare; balance = balance + amt + bonus; } // use card once, returns message public String useonce() { if (balance>=fare) { balance -= fare; return "have a nice ride, avoid the rats"; } else return "funds too low"; } public String swipe() { return useonce(); } // alias for usecard // transfer balance of 'this' card to othercard public void transfer(metrocard othercard) { othercard.balance += this.balance; // this is for emphasis this.balance = 0; } public String toString() // override Object.toString() { return "Metrocard with balance "+balance; } public static void changefare(double diff) // why static? { fare += diff; } // static test function, to be called from main public static void test() { metrocard mycard = new metrocard(3); metrocard myothercard = new metrocard(5); mycard.useonce(); myothercard.swipe(); mycard.refill(11); // should get bonus System.out.println(mycard); mycard.transfer(myothercard); System.out.println(myothercard); metrocard.changefare(0.25); // raise fare by 25 cents } }//metrocard class /////////////////////// see main for usage //// Example 2: date, representing a month, day and year. This time, // our class will implement an interface (Comparable), which // means it has to implement a int compareTo(date x) function. Interfaces // allow 'polymorphism': for example, when writing a sorting procedure we // want to be able to sort all objects that implement the compareTo function. class date implements Comparable { protected int year; protected int month; protected int day; // number of days in each month (non-leap years) protected static final int[] DIM={31,28,31,30,31,30,31,31,30,31,30,31}; // constructor takes month, day, year: public date(int m, int d, int y) { if (m<1 || m>12 || d<1 || d>DIM[m-1]) throw new RuntimeException("invalid date"); this.year = y; month=m; day = d; // 'this' is optional }// constructor protected int daysInMonth() // calculate number of days in month. { int d = DIM[month-1]; if (month==1 && year%4==0 && year%400!=0) d++; // for February return d; } public String toString() { return month+"/"+day+"/"+year; } public String toEuropean() { return day+","+month+","+year; } // euro style // destructively advance date to next day: public void nextday() { int dim = daysInMonth(); day++; if (day>dim) { month++; day = 1;} if (month>12) { year++; month= 1; } } public date dayafter() // NON-DESTRUCTIVE version of nextday { int dim = daysInMonth(); int d=day , m=month, y=year; // new day, month, year values d++; if (d>dim) { m++; d=1; } if (m>12) { y++; m=1; } return new date(m,d,y); } // compare this date with date B, return - for <, 0 for ==, + for > public int compareTo(date B) { // first compare the year: if (year != B.year) return year-B.year; // if years are same, compare month: if (month != B.month) return month - B.month; // if year and month are both same, compare day: return day - B.day; // alternatively, can use the following: // return year*(12*32)+month*32+day - B.year*(12*32)+B.month*32+B.day; } public static void test() { date d1 = new date(2,28,2019); d1.nextday(); System.out.println(d1); // should print 3/1/2019 System.out.println(new date(12,31,2018).dayafter()); // 1/1/2019 } }//date class //// Example 3: Fractions such as 1/2, 2/3, etc. class fraction implements Comparable { protected int num; // numerator protected int denom; // denominator; public fraction(int n, int d) { if (d==0) throw new RuntimeException("zero denominator"); num = n; denom = d; } public String toString() // override Object.toString { return num+"/"+denom; } public static int gcd(int a, int b) // greatest common divisor { if (a==0) return b; else return gcd(b%a,a); // RECURSION OK HERE /* non-recursive version: while (a!=0) { int tmp = a; a = b%a; b = tmp; } return b; */ } public void simplify() // destructively simplify fraction, 2/4 --> 1/2 { int divisor = gcd(num,denom); num = num/divisor; denom = denom/divisor; } // non-destructive addition: a/b + c/d = (a*d+c*b) / b*d public fraction add(fraction B) { int a=num, b=denom, c= B.num, d=B.denom; return new fraction(a*d+c*b, b*d); } // non-destructive multiplication: a/b * c/d = a*c / b*d public fraction mult(fraction B) { int a=num, b=denom, c= B.num, d=B.denom; return new fraction(a*c,b*d); } // non-destructive inverse public fraction invert() { return new fraction(denom,num); } public boolean equals(fraction B) { return this.compareTo(B)==0; // 'this' is optional } public int compareTo(fraction B) // consistent with equals { return num*B.denom - denom*B.num; } public static void test() // testing fractions (call from main) { fraction half = new fraction(1,2); fraction third = new fraction(1,3); System.out.println(half.add(third)); // 5/6 fraction f3 = new fraction(2,6); System.out.println(f3.equals(third)); // true f3.simplify(); System.out.println(f3); // 1/3 } }//fraction ///// public class with main public class objectexamples { public static void main(String[] av) { metrocard.test(); // test metrocard class date.test(); fraction.test(); // time.test(); // uncomment when done with exercise below }//main }