//DatesArrayListTest.java //create list of random Dates. iterate over and increment them. sort them. //Date and IncDate are in this file for a standalone demo program. //2 Date Comparators are here too for sorting. /* An Iterator's next() method returns a reference of built-in class Object. If you want to use that reference to access a member of your class, you must cast that return value to your class: Date thisDate = (Date)(it.next()); then you can access methods of the Date object: thisDate.monthIs() Failure to cast will be an "incompatible types" compile error, Date thisDate = it.next(); Directly trying to use the it.next() to access a Date method is a "cannot find symbol method" compile error: it.next().monthIs(); as the Object class does not have a monthIs member. To access a method only of the IncDate subclass, the Date reference must be cast to be an IncDate after checking that it is indeed an IncDate reference using the instanceof operator: if (thisDate instanceof IncDate) { //***downcast to subclass to access a method of subclass: ((IncDate)thisDate).increment(); Failure to check that the superclass reference variable actually is a reference to a subclass IncDate object results in a runtime ClassCastException when the reference is actually to a superclass Date object. Failure to "downcast" the Date reference to the subclass IncDate thisDate.increment(); is a "cannot find symbol method" compile error, as the Date class does not have an increment member. But but how can System.out.println be given an Object reference: System.out.println(it.next()); and the Date toString method is called? Object is the superclass of all other classes. Date, for example, is a subclass of Object, it extends Object automatically, without any need of the extends clause. Object is the ancestor of all classes, and so all classes inherit its methods such as toString. println is (indirectly) calling the toString method of Object but if a class has overridden the toString method inherited from Object and the reference is actually to an object of that class, then the overridden method is called. This is the deep magic of polymorphism: a superclass reference like it.next() can be used to access subclass methods. More on this later. */ import java.util.*; import javax.swing.*; public class DatesArrayListTest { public static void main(String[] args) { String input; int size; ArrayList myDatesList = new ArrayList(); input = JOptionPane.showInputDialog( "Enter number of random dates" ); size = Integer.parseInt( input ); //**array list of Dates and IncDates for (int i=1; i<=size; i++) { myDatesList.add(generateRandomDate()); //**pseudo data... } //iterate over them, incrementing each IncDate Iterator it=myDatesList.iterator(); System.out.println(); System.out.println("Here are your dates: (IncDates get incremented) "); //***superclass reference variable can hold reference to superclass or to subclasses: Date thisDate; while (it.hasNext()) { //reference to the Date in the list. (IncDate IS-A Date too) //***next() returns Object, cast to Date (superclass of IncDate) thisDate = (Date)(it.next()); System.out.print(thisDate); //***check if object is actually an IncDate: if (thisDate instanceof IncDate) { //***downcast to subclass to access a method of subclass: ((IncDate)thisDate).increment(); System.out.println(" " + thisDate); //incremented } else //Date System.out.println(); //newline for the un-incremented Date } System.out.println(); //what does sorting do to Dates? //Collections.sort(myDatesList); //***runtime error. //***there is no "natural ordering" for user-defined classes. //***must specify how dates are compared with a Comparator. //DateComparator is defined below. Collections.sort(myDatesList,new DateComparator()); //*** it = myDatesList.iterator(); System.out.println("Here are your dates in sorted order: "); while (it.hasNext()) { System.out.println(it.next()); } System.out.println(); //***now sort by julian day using a different comparator Collections.sort(myDatesList,new DateComparatorJulian()); //*** it = myDatesList.iterator(); System.out.println("Here are your dates in julian sorted order: "); while (it.hasNext()) { System.out.println(it.next()); } System.out.println(); System.exit(0); } //generate a random Date or IncDate. //***return type is superclass. actual returned object can be any subclass too. public static Date generateRandomDate() { int year, month, day=0; year = (int)(Math.random()*20+1995); // +/- 10 years from 2005 month = (int)(Math.random()*12+1); switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: day = (int)(Math.random()*31+1); break; case 4: case 6: case 9: case 11: day = (int)(Math.random()*30+1); break; case 2: if (year%4==0 && year%100!=0 || year%400==0) //leap year test day = (int)(Math.random()*29+1); else day = (int)(Math.random()*28+1); break; } //*** 50 50 whether it's Date or IncDate if (Math.random() < .5) return new Date(month,day,year); else return new IncDate(month,day,year); } } class Date //same as in ch01 { protected int year; protected int month; protected int day; public Date(int newMonth, int newDay, int newYear) { month = newMonth; day = newDay; year = newYear; } public int yearIs() { return year; } public int monthIs() { return month; } public int dayIs() { return day; } public String toString() { return(month + "/" + day + "/" + year); } } class IncDate extends Date //same as in ch01 { public IncDate(int newMonth, int newDay, int newYear) { super(newMonth, newDay, newYear); } public void increment() { // increment algorithm goes here // it updates the year, month, and day attributes day = day + 1; } } //*************************************************** //**comparator for specifying how to compare Dates. //calendar year order... //***your class implementing Comparator interface which requires the compare method class DateComparator implements Comparator { //***must be this signature. //***return 0 if equal, positive if a>b, negative if a d2.yearIs()) return 1; else if (d1.yearIs() < d2.yearIs()) return -1; else if (d1.monthIs() > d2.monthIs()) return 1; else if (d1.monthIs() < d2.monthIs()) return -1; else if (d1.dayIs() > d2.dayIs()) return 1; else if (d1.dayIs() < d2.dayIs()) return -1; else return 0; } } //***this comparator compares Dates by julian day within the year class DateComparatorJulian implements Comparator { //must be this signature: //return 0 if equal, positive if a>b, negative if a d2.monthIs()) return 1; else if (d1.monthIs() < d2.monthIs()) return -1; else if (d1.dayIs() > d2.dayIs()) return 1; else if (d1.dayIs() < d2.dayIs()) return -1; else return 0; } }