4 Last Class, Concluded TestingTesting is a major part of quality assurance (QA)QA includes other activities:Dynamic analysis (monitor program execution)E.g., tools like DrMemory, MemcheckStatic analysis (find bugs without execution)Many tools for C/C++ with focus on memory errorsTools for Java that catch null pointer errors, unwanted mutation, etc.Proofs of correctness (theorems)Code reviews (people reading each other’s code)

6 Equality Simple idea: Many subtleties2 objects are equal if they have the same valueMany subtletiesSame reference, or same value?Same rep or same abstract value?Remember the HW3 questionsEquality in the presence of inheritance?Does equality hold just now or is it eternal?How can we implement equality efficiently?Spring 15 CSCI 2600, A Milanova

7 Equality: == and equalsJava uses the reference model for class typesclass Point {int x; // x-coordinateint y; // y-coordinatePoint(int x, int y) {this.x = x;this.y = y;}a = new Point(2,5);b = new Point(2,5);c = b;ab2525cHence, there are 2 ways (at least) to test for equality!== is the reference equality. Returns true of the 2 references point to the same object..equals() is the “value” equality. It may relaxes the reference equality. If it is defined in a class, it specifies what it means for two objects of this class to be “equal”. If it is not defined in a class, then the class inherits Object.equals, which implements reference equality.x == y is falsey == z is truex.equals(y) is falsey.equals(z) is truetrue or false? a == b ?true or false? b == c ?true or false? a.equals(b) ?true or false? b.equals(c) ?

8 Equality: == and equalsIn Java, == tests for reference equality. This is the strongest form of equalityUsually we need a weaker form of equality, value equalityIn our Point example, we want a to be “equal” to b because the a and b objects hold the same valueNeed to override Object.equalsbcab2525Spring 15 CSCI 2600, A Milanova

11 Object.equals Javadoc specIndicates whether some other object is "equal to" this one. The equals method implements an equivalence relation:It is reflexive: for any non-null reference value x, x.equals(x) should return true.It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.

12 Object.equals Javadoc specFor any non-null reference value x, x.equals(null) should return false. The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true)… Parameters: obj - the reference object with which to compare. Returns: true if this object is the same as the obj argument; false otherwise. See Also: hashCode(), HashMap

13 The Object.equals Spec Why this complex specification? Why not justreturns: true if obj == this, false otherwiseObject is the superclass for all Java classesThe specification of Object.equals must be as weak (i.e., general) as possibleSubclasses must be substitutable for ObjectThus, subclasses need to provide stronger equalsobj == this is too strong, the strongest form of equality! Places undue restriction on subclasses: no subclass can weaken equals and still be substitutable for Object!The spec lists the basic properties of equality, the weakest possible specification of equals

24 Another Solution: Compositionpublic class NanoDuration {private final Duration duration;private final int nano;…}Composition does solve the equals problem: Duration and NanoDuration are now unrelated, so we’ll never compare a Duration to a NanoDurationProblem: Can’t use NanoDuration instead of Duration. Can’t reuse code written for Duration.Spring 15 CSCI 2600, A Milanova (example due to Michael Ernst)

25 A Reason to Avoid Subclassing Concrete Classes. More laterIn the JDK, subclassing of concrete classes is rare. When it happens, there are problemsOne example: Timestamp extends DateExtends Date with a nanosecond valueBut Timestamp spec lists several caveatsE.g., Timestamp.equals(Object) method is not symmetric with respect to Date.equals(Object)(the symmetry problem we saw on slide 20)

26 Abstract ClassesThere is no equality problem if superclass cannot be instantiated!E.g., if Duration were abstract, the issue of comparing Duration and NanoDuration never arisesPrefer subclassing abstract classesJust like in real life. “Superclasses” in real life cannot be instantiatedSpring 15 CSCI 2600, A Milanova (based on a slide by Michael Ernst)

28 The int hashCode MethodhashCode computes an index for the object (to be used in hashtables)Javadoc for Object.hashCode():“Returns a hash code value of the object. This method is supported for the benefit of hashtables such as those provided by HashMap.”Self-consistent: o.hashCode() == o.hashCode()… as long as o does not change between the callsConsistent with equals() method: a.equals(b) => a.hashCode() == b.hashCode()

29 The Object.hashCode MethodObject.hashCode’s implementation returns a distinct integer for each distinct object, typically by converting the object’s address into an integerhashCode must be consistent with equalityequals and hashCode are used in hashtablesIf hashCode is inconsistent with equals, the hashtable behaves incorrectlyRule: if you override equals, override hashCode; must be consistent with equals

30 Implementations of hashCodeRemember, we defined Duration.equals(Object)public class Duration {Choice 1: don’t override, inherit hashCode from ObjectChoice 2: public int hashCode() { return 1; }Choice 3: public int hashCode() { return min; }Choice 4: public int hashCode() { return min+sec; }}Choice 1: hashCode is inconsistent with equals.One of the most common mistakes by Java programmers is to override equals but not override hashCode.Choice 2: consistent with equals, but inefficient, groups all Duration objects into one bucket.Choice 3: consistent with equals, better prefiltering, but still inefficient because groups all durations with same min into one bucket.Choice 4: consistent with equals. Even better, will tend to change the hashCode as object value changes.Spring 15 CSCI 2600, A Milanova

31 hashCode Must Be Consistent with equalsSuppose we change Duration.equals// Returns true if o and this represent the same number of// secondspublic boolean equals(Object o) {if (!(o instanceof Duration)) return false;Duration d = (Duration) o;return 60*min+sec == 60*d.min+d.sec;}Can we leave hashCode be one of the implementations on the previous slide we deemed consistent?Choice 1 is inconsistent.Choice 2 is consistent, but not good because it groups all Durations in one bucket.Choice 3 is inconsistent, because we may have min:0, sec: 90 and min: 1, sec: 30, which are equal according to the new definition. Thus, we’ll have a.equals(b) true but a.hashCode == b.hashCode false, i.e., inconsistent.Choice 4 is inconsistent too because we again again may have a.equals(b) not imply a.hashCode == b.hashCode.We need to redefine hashCode. What will be a good one? return 60*min+sec.Spring 15 CSCI 2600, A Milanova (slide by Mike Ernst)