Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Typically, errors manifest when assumptions are made about the implementation specific details of the superclass. Here, the two objects are compared for equality in the overriding after() method and subsequently, the superclass's after() method is explicitly called to take over. The issue is that the superclass Calendar's after() method internally uses class Object's compareTo() method. Consequently, the superclass's after() method erroneously invokes the subclass's version of compareTo() due to polymorphism. Since the subclass is unaware of the superclass's implementation of after(), it does not expect any of its own overriding methods to get invoked. The guideline MET32-J. Ensure that constructors do not call overridable methods describes similar programming errors.

Code Block
bgColor#FFCCCC
class CalendarSubclass extends Calendar {
  @Override public boolean after(Object when) {
    if(when instanceof Calendar && super.compareTo((Calendar)when) == 0)
        // correctly calls Calendar.compareTo()
      return true;
    return super.after(when); // calls CalendarSubclass.compareTo() due to polymorphism
  }
	
  @Override public int compareTo(Calendar anotherCalendar) {
    // This method is erroneously invoked by Calendar.after()
    return compareTo(anotherCalendar.getFirstDayOfWeek(),anotherCalendar);
  }

  private int compareTo(int firstDayOfWeek, Calendar c) {
    int thisTime = c.get(Calendar.DAY_OF_WEEK);
    return (thisTime > firstDayOfWeek) ? 1 : (thisTime == firstDayOfWeek) ? 0 : -1;
  }

  public static void main(String[] args) {
    CalendarSubclass cs1 = new CalendarSubclass();
    CalendarSubclass cs2 = new CalendarSubclass();
    cs1.setTime(new Date());
    System.out.println(cs1.after(cs2));  // prints false
  }

/* Implementation of other abstract methods */
}

// The implementation of java.util.Calendar.after() method is shown below
public boolean after(Object when) {
  return when instanceof Calendar && compareTo((Calendar)when) > 0;
     // forwards to the subclass's implementation erroneously
}

...