Note about equals.

 

Executive summary

The interfaces with equals(Course) and equals(Student) cause a problem; but the problem can be solved.

Problem Description

In Assignment 1, the interfaces Course and Student contained equals methods which were not fully polymorphic, as in
boolean equals (Course c);
The fully polymorphic equals would have the signature:
boolean equals (Object c);
Several students noted that this causes a problem when Course or Student objects are used in container classes such ListImpl.  The problem arises as follows:
  1. suppose there's a class C with a method equals(C x), apparently for comparing two C objects for equality;
  2. suppose a container class S has a method inContainer(Object o), apparently for testing if a given Object is in the container currently;
  3. suppose c1 is declared of type C and h1 is declared of type S.
  4. then the call h1.inContainer(c1) will not use the C.equals(C x), despite dynamic dispatching; instead it will use Object.equals(Object x), and S.inContainer will return the wrong result.
Why does this happen?  Well, the code for inContainer probably has within it something like
...
if (o. equals (m))
    ...
which compares the given o to some local Object m.  It uses a method of o which must have the signature equals(Object x), because that's how it's called.  Even though o sometimes refers to an instance of C during execution, it is not generally true that o refers to something with a method equals(C x) - so Java doesn't arrange to call such a method ever.

Solution

The solution is - never define a non-polymorphic equals, and never specify one in an interface, either.

If you must define one, because you have an interface which requires it, then define the fully polymorphic one to use the nonpolymorphic one:

boolean equals (Course c)   // new method, for interface
{
    return this. title. equals (c. title);
}
boolean equals (Object c)   // override inherited signature
{
    if (c instanceof Course)
        return equals ((Course) c);
    else
        return false;       // not the same type, can't be equal
}