Apples and Oranges


Since the equals method takes an Object as parameter, you can pass anything to it (and the code will still compile). Your equals method should handle this situation:

 // apples & oranges assertFalse(courseA.equals("CMSC-120")); 

Even though the String value matches the department and number of courseA, a Course is not a String. You would expect this comparison to return false. When Java executes the equals method, however, you receive a ClassCastException. The line of the equals method that executes the cast is the cause:

 @Override public boolean equals(Object object) {    if (object == null)       return false;    Course that = (Course)object;    return       this.department.equals(that.department) &&       this.number.equals(that.number); } 

The code attempts to cast the String parameter to a Course reference. This invalid cast generates the ClassCastException.

You need a guard clause that immediately returns false if someone throws an orange at your equals method. The guard clause ensures that the type of the parameter matches the type of the receiver.

 @Override public boolean equals(Object object) {    if (object == null)       return false;    if (this.getClass() != object.getClass())       return false;    Course that = (Course)object;    return       this.department.equals(that.department) &&       this.number.equals(that.number); } 

You learned about the getClass method in Lesson 8. It returns a class constant. For the example comparison that threw the ClassCastException, the class constant of the receiver is Course.class, and the class constant of the parameter is String.class. Class constants are uniquethere is only one "instance" of the Class object Course.class. This uniqueness allows you to compare class constants using the operator != (not equal to) instead of comparing them using equals.

Some developers choose to use the instanceof operator. The instanceof operator returns true if an object is an instance of, or subclass of, the target class. Here is the equals method rewritten to use instanceof.

 @Override public boolean equals(Object object) {    if (object == null)       return false;    if (!(object instanceof Course))       return false;    Course that = (Course)object;    return       this.department.equals(that.department) &&       this.number.equals(that.number); } 

You should initially prefer to compare the classes of the receiver and argument, instead of using instanceof. The class comparison only returns true if both objects are of the exact same type. Introduce instanceof later if you need to compare objects irrespective of their position in an inheritance hierarchy. See Lesson 12 for more information on instanceof.

JUnit and Equality

Sometimes I will code equals tests to be a bit more explicit. Instead of saying:

 assertEquals(courseA, courseB); 

I'll express the comparison as:

 assertTrue(courseA.equals(courseB)); 

You should be clear on the fact that assertEquals uses the equals method for reference comparisons. But it can be helpful to explicitly emphasize that fact, and show that the equals method is what you're actually testing.

You may want to compare two references to see if they are the same. In other words, do they point to the same object in memory? You could code this comparison as:

 assertTrue(courseA == courseB); 

or as:

 assertSame(courseA, courseB); 

You should prefer the second assertion form, since it supplies a better error message upon failure. As before, though, you might choose to explicitly show the == comparison if for purposes of building an equals method test.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net