Effective Java. Object Equality. - Case Studies - Angelika Langer. Trainer/Consultant.

Similar documents
The class Object. Lecture CS1122 Summer 2008

Programming Languages and Techniques (CIS120)

The Object Class. java.lang.object. Important Methods In Object. Mark Allen Weiss Copyright 2000

Creating an Immutable Class. Based on slides by Prof. Burton Ma

The Liskov Substitution Principle

Programming Languages and Techniques (CIS120)

equals() in the class Object

Super-Classes and sub-classes

CSE 331 Software Design & Implementation

Expected properties of equality

MET08-J. Preserve the equality contract when overriding the equals() method

For this section, we will implement a class with only non-static features, that represents a rectangle

Canonical Form. No argument constructor Object Equality String representation Cloning Serialization Hashing. Software Engineering

Chapter 11: Collections and Maps

CSE 331 Software Design & Implementation

java.lang.object: Equality

Programming Languages and Techniques (CIS120e)

Equality. Michael Ernst. CSE 331 University of Washington

Methods Common to all Classes

Equality. Michael Ernst. CSE 331 University of Washington

Java Fundamentals (II)

CS/ENGRD 2110 FALL Lecture 6: Consequence of type, casting; function equals

Software Engineering Design & Construction

Polymorphism. return a.doublevalue() + b.doublevalue();

Inheritance (Part 5) Odds and ends

Programming Languages and Techniques (CIS120)

CMSC 132: Object-Oriented Programming II

Contents. I. Classes, Superclasses, and Subclasses. Topic 04 - Inheritance

COMP 250 Fall inheritance Nov. 17, 2017

Implementing Object Equivalence in Java Using the Template Method Design Pattern

CS-202 Introduction to Object Oriented Programming

Principles of Software Construction: Objects, Design and Concurrency. Inheritance, type-checking, and method dispatch. toad

Class, Variable, Constructor, Object, Method Questions

Announcements. Equality. Lecture 10 Equality and Hashcode. Announcements. CSE 331 Software Design and Implementation. Leah Perlmutter / Summer 2018

1 Shyam sir JAVA Notes

INSTRUCTIONS TO CANDIDATES

Collections. Powered by Pentalog. by Vlad Costel Ungureanu for Learn Stuff

INHERITANCE. Spring 2019

Inheritance -- Introduction

Inheritance. Lecture 11 COP 3252 Summer May 25, 2017

Principles of Software Construction: Objects, Design and Concurrency. Polymorphism, part 2. toad Fall 2012

Lecture 36: Cloning. Last time: Today: 1. Object 2. Polymorphism and abstract methods 3. Upcasting / downcasting

Programming Languages and Techniques (CIS120)

More On inheritance. What you can do in subclass regarding methods:

Motivations. Chapter 13 Abstract Classes and Interfaces

Chapter 13 Abstract Classes and Interfaces. Liang, Introduction to Java Programming, Tenth Edition, Global Edition. Pearson Education Limited

Domain-Driven Design Activity

Inheritance and Polymorphism

Computer Science II (20073) Week 1: Review and Inheritance

Name Return type Argument list. Then the new method is said to override the old one. So, what is the objective of subclass?

More about inheritance

MIT EECS Michael Ernst Saman Amarasinghe

COE318 Lecture Notes Week 8 (Oct 24, 2011)

CMSC 132: Object-Oriented Programming II. Effective Java. Department of Computer Science University of Maryland, College Park

Motivations. Objectives. object cannot be created from abstract class. abstract method in abstract class

09/02/2013 TYPE CHECKING AND CASTING. Lecture 5 CS2110 Spring 2013

Conversions and Casting

Programming Languages and Techniques (CIS120)

F I N A L E X A M I N A T I O N

DOWNLOAD PDF CORE JAVA APTITUDE QUESTIONS AND ANSWERS

Graphical Interface and Application (I3305) Semester: 1 Academic Year: 2017/2018 Dr Antoun Yaacoub

Chapter 11 Inheritance and Polymorphism. Motivations. Suppose you will define classes to model circles,

COMP 250. Lecture 30. inheritance. overriding vs overloading. Nov. 17, 2017

Inheritance. The Java Platform Class Hierarchy

Software Construction

C12a: The Object Superclass and Selected Methods

VIRTUAL FUNCTIONS Chapter 10

Today. Book-keeping. Inheritance. Subscribe to sipb-iap-java-students. Slides and code at Interfaces.

Programming II (CS300)

Chapter 13 Abstract Classes and Interfaces

Advanced Programming - JAVA Lecture 4 OOP Concepts in JAVA PART II

Polymorphism. CMSC 330: Organization of Programming Languages. Two Kinds of Polymorphism. Polymorphism Overview. Polymorphism

Inheritance and Interfaces

CS 112 Programming 2. Lecture 10. Abstract Classes & Interfaces (1) Chapter 13 Abstract Classes and Interfaces

CS107 Handout 37 Spring 2007 May 25, 2007 Introduction to Inheritance

Subclasses, Superclasses, and Inheritance

CSCI-142 Exam 1 Review September 25, 2016 Presented by the RIT Computer Science Community

Inheritance. Inheritance Reserved word protected Reserved word super Overriding methods Class Hierarchies Reading for this lecture: L&L

Chapter 10 Inheritance and Polymorphism. Dr. Hikmat Jaber

Abstract Classes and Interfaces

Equality in.net. Gregory Adam 07/12/2008. This article describes how equality works in.net

Introduction to Inheritance

First IS-A Relationship: Inheritance

IST311. Advanced Issues in OOP: Inheritance and Polymorphism

Announcement. Agenda 7/31/2008. Polymorphism, Dynamic Binding and Interface. The class will continue on Tuesday, 12 th August

Late-bound Pragmatical Class Methods

A Short Summary of Javali

AP COMPUTER SCIENCE JAVA CONCEPTS IV: RESERVED WORDS

Inheritance. Inheritance allows the following two changes in derived class: 1. add new members; 2. override existing (in base class) methods.

Example: Count of Points

Advanced Topics on Classes and Objects

Agenda. Objects and classes Encapsulation and information hiding Documentation Packages

Rules and syntax for inheritance. The boring stuff

CLASS DESIGN. Objectives MODULE 4

Object Oriented Programming. Java-Lecture 11 Polymorphism

Inheritance. Notes Chapter 6 and AJ Chapters 7 and 8

Software Engineering Design & Construction Dr. Michael Eichberg Fachgebiet Softwaretechnik Technische Universität Darmstadt

Java Classes. Produced by. Introduction to the Java Programming Language. Eamonn de Leastar

Defective Java Code: Turning WTF code into a learning experience

Outline. Inheritance. Abstract Classes Interfaces. Class Extension Overriding Methods Inheritance and Constructors Polymorphism.

Transcription:

Effective Java Object Equality - Case Studies - Angelika Langer Trainer/Consultant objective study different implementations of equals() identify and evaluate different techniques object equality - case studies (2) 1

comparison of reference variables can mean two things: check for identity of referenced objects check for equality of referenced objects identical objects: occupy same memory location are effectively the "same" object equal objects: behave in the same way often means: have same state or content object equality - case studies (3) comparison of reference variables check for identity via operator == yields true if 8operand values both null, or 8both refer to same object or array check for equality via method boolean equals(object o) inherited from class Object 8can be overridden to implement a check for equality 8default provided by Object.equals(): check for identity! semantics class-specific 8depends on implementation object equality - case studies (4) 2

example: class-specific semantics of equals() class StringBuffer does not override equals() class String does String s = Hello World! ; String s1 = new String(s); String s2 = new String(s); true if ( s1.equals(s2) ) StringBuffer sb1 = new StringBuffer(s); StringBuffer sb2 = new StringBuffer(s); false if ( sb1.equals(sb2) ) object equality - case studies (5) which classes must override equals()? fundamental distinction between value types non-value types (sometimes called entity types) value types have content and behavior depends vitally on this content examples: BigDecimal, String, Date, Point, etc. entity types behavior not strictly determined by content 8service-based types 8handles to an underlying object examples: Thread, FileOutputStream, entity beans in EJB object equality - case studies (6) 3

which classes must override equals()? entity types do not override Object.equals() comparing content is pointless, is not relevant anyway value types override Object.equals() equality means "equal content significant difference between identity and equality recommendation: Classes that represent value types must override Object.equals(). object equality - case studies (7) requirements obvious requirement (to an implementation of equals() for a value type) check for equality of objects additional requirements imposed by JDK stem from HashSet and HashMap have certain expectations; do not work properly otherwise defined in the so-called equals() contract see documentation of Java platform libraries object equality - case studies (8) 4

the equals() contract reflexivity for any reference value x, x.equals(x) should return true symmetry for any reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true transitivity for any 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 consistency for any 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 object is modified non-nullity for any non-null reference value x, x.equals(null) should return false object equality - case studies (9) lack of compliance failure to comply to the equals() contract leads to subtle bugs 8difficult to track down because they are conceptual problems 8conceptual problem are not detected by debugging source code not only hash-based collections rely on reflexivity, symmetry, and transitivity 8everybody who calls equals() does recommendation: Never provide an implementation of equals() that does not comply to the equals() contract. object equality - case studies (10) 5

implementing equals() different techniques for implementing equals() study a number of sample implementations that have been published [1] "Program Development in Java" by Barbara Liskov [2] "Effective Java" by Joshua Bloch [3] "Practical Java" by Peter Haggar [4] JDK 1.3 source code (authors: James Gosling, Arthur van Hoff, Alan Liu) object equality - case studies (11) Barbara Liskov, "Program Development in Java", page 182 public class Point3 extends Point2 { private int z; public boolean equals(object p) { // overriding definition if (p instanceof Point3) return equals((point3)p); return super.equals(); public boolean equals(point2 p) { // overriding definition if (p instanceof Point3) return equals((point3)p); return super.equals(); public boolean equals(point3 p) { // extra definition if (p==null z!=p.z) return false; return super.equals(); object equality - case studies (12) 6

7 JDK 1.3, package java.util, class Date public class Date implements java.io.serializable, Cloneable, Comparable { private transient Calendar cal; private transient long fasttime; private static Calendar staticcal = null; // lots of static fields public long gettime() { return gettimeimpl(); private final long gettimeimpl() { return (cal == null)? fasttime : cal.gettimeinmillis(); public boolean equals(object obj) { return obj instanceof Date && gettime() == ((Date) obj).gettime(); object equality - case studies (13) Josh Bloch, "Effective Java", item 7 and item 8 public final class PhoneNumber { private final short areacode; private final short exchange; private final short extension; public boolean equals(object o) { if (o==this) return true; if (!(o instanceof PhoneNumber)) return false; PhoneNumber pn = (PhoneNumber)o; return pn.extensions == extension && pn.exchange == exchange && pn.areacode == areacode; object equality - case studies (14)

Peter Haggar, "Practical Java", praxis 8 thru praxis 14 class Golfball { private String brand; private String make; private int compression; public String brand() { return brand; public boolean equals(object obj) { if (this == obj) return true; if (obj!=null && getclass() == obj.getclass()) { Golfball gb = (Golfball)obj; // Classes are equal, downcast. if (brand.equals(gb.brand()) && // Compare atrributes. make.equals(gb.make()) && compression == gb.compression()) return true; return false; object equality - case studies (15) Peter Haggar (cont.) class MyGolfball extends Golfball { public final static byte TwoPiece = 0; public final static byte ThreePiece = 1; private byte ballconstruction; public byte constuction() { return ballconstruction; public boolean equals(object obj) { if (super.equals(obj)) { MyGolfball bg = (MyGolfball)obj; // Classes equal, downcast. if (ballconstruction == gb.construction()) return true; return false; object equality - case studies (16) 8

different techniques signature disagreement: 8overriding in combination with overloading several versions of equals() method (Listing 1) 8just one signature namely Object.equals(Object o) comparing fields agreement: 8equals() must compare fields defined in the class if fields contribute to state of object transient and static fields are not considered (see Listing 2) object equality - case studies (17) different techniques delegation to super agreement: 8super.equals() should be invoked 8if class has a superclass other than Object type check and downcast agreement: 8check that other object is of a type to which this object can be compared disagreement regarding the actual check: 8use instanceof operator 8use getclass() method (see Listing 4) object equality - case studies (18) 9

agenda check for type match delegation vs. inheritance signature of equals() slice comparison yes/no correct slice comparison methods guidelines for practitioners object equality - case studies (19) listing 1 - an incorrect implementation public class Point3 extends Point2 { private int z; public boolean equals(object p) { // overriding definition if (p instanceof Point3) return equals((point3)p); return super.equals(); public boolean equals(point2 p) { // overriding definition if (p instanceof Point3) return equals((point3)p); return super.equals(); public boolean equals(point3 p) { // extra definition if (p==null z!=p.z) return false; return super.equals(); not transitive object equality - case studies (20) 10

11 mixed-type comparison Point2 origin(0,0); Point3 p1(0,0,-1); point3 p2(0,0,1); System.out.println(p1.equals(origin)); // calls Point3.equals(Point2) System.out.println(origin.equals(p2)); // calls Point2.equals(Point2) System.out.println(p1.equals(p2)); // calls Point3.equals(Point3) should print: true true true Point2 origin (0,0) instead prints: true true false Point3 p1 (0,0,-1) Point3 p2 (0,0,1) object equality - case studies (21) lack of transitivity - reason equals() methods in Point2 and Point3 perform semantically different comparisons mixed-type comparison involving a superclass and a subclass object slice comparison: comparing only superclass part same-type comparison involving two subclass objects whole-object comparison object equality - case studies (22)

conceptual problem in class hierarchies equals() must be transitive equals() must compare for equality of objects objects in a class hierarchy have a different structure: subclass objects have more fields than superclass objects subclass must implement equals() 8take subclass-specific fields into account subclass equals() semantically different from superclass version if equals() permits mixed-type comparison it is non-transitive (and incorrect) alternatives: do not allow slice comparison of superclass and subclass objects equals() method is final in the superclass object equality - case studies (23) listing 2 - a debatable implementation public class Date implements java.io.serializable, Cloneable, Comparable { private transient Calendar cal; private transient long fasttime; private static Calendar staticcal = null; // lots of static fields public long gettime() { return gettimeimpl(); private final long gettimeimpl() { return (cal == null)? fasttime : cal.gettimeinmillis(); public boolean equals(object obj) { return obj instanceof Date && gettime() == ((Date) obj).gettime(); subclasses are in trouble object equality - case studies (24) 12

13 a subclass - example implementation of subclass and its equals(): public class NamedDate extends Date { private String name; public boolean equals(object other) { if (other instanceof NamedDate &&!name.equals(((nameddate)other).name)) return false; return super.equals(other)); implementation of superclass equals(): public class Date implements { public boolean equals(object obj) { return obj instanceof Date && gettime() == ((Date) obj).gettime(); object equality - case studies (25) mixed-type comparison NamedDate EndOfMillenium = new NamedDate(99,11,31,"end of 2 nd NamedDate TheEnd = new NamedDate(99,11,31,"end of the world"); Date NewYearsEve = new Date(99,11,31); millenium AC"); EndOfMillenium.equals(NewYearsEve) NewYearsEve.equals(TheEnd) EndOfMillenium.equals(TheEnd) // slice comparison: true // slice comparison: true // whole-object comparison: false Date NewYearsEve not transitive 12/31/1999 NamedDate TheEnd 12/31/1999 end of the world NamedDate EndOfMillenium 12/31/1999 end of 2nd millenium AC object equality - case studies (26)

evaluation same transitivity problem as before Date.equals() allows for slice comparison overriding versions in a subclass performs semantically different comparison incorrect non-transitive behavior class Date can avoid pitfall by declaring equals() method final by declaring entire class final object equality - case studies (27) another common mistake another implementation of a subclass: public class NamedDate extends Date { private String name; public boolean equals(object other) { if (!(other instanceof NamedDate) ) return false; else if (!name.equals(((nameddate)other).name) ) return false; else if (!super.equals(other) ) return false; else return true; object equality - case studies (28) 14

15 asymmetry mixed-type comparison compare Date to NamedDate via Date.equals() 8NamedDate passes instanceof test 8comparison is performed; result can be false or true swap the two objects: 8compare NamedDate to Date via NamedDate.equals() 8Date object does not pass instanceof test 8these two objects will never compare equal violates the symmetry requirement fairly common in Java platform library classes before JDK 1.3 object equality - case studies (29) listing 3 - a correct implementation public final class PhoneNumber { private final short areacode; private final short exchange; private final short extension; public boolean equals(object o) { if (o==this) return true; if (!(o instanceof PhoneNumber)) return false; PhoneNumber pn = (PhoneNumber)o; return pn.extensions == extension && pn.exchange == exchange && pn.areacode == areacode; object equality - case studies (30)

evaluation equals() uses instanceof test class PhoneNumber is final no subclasses can ever exists transitivity problem can never come up flawless solution, but restricted to final classes object equality - case studies (31) listing 4 - another correct implementation class Golfball { private String brand; private String make; private int compression; public String brand() { return brand; public boolean equals(object obj) { if (this == obj) return true; if (obj!=null && getclass() == obj.getclass()) { Golfball gb = (Golfball)obj; // Classes are equal, downcast. if (brand.equals(gb.brand()) && // Compare atrributes. make.equals(gb.make()) && compression == gb.compression()) return true; return false; object equality - case studies (32) 16

17 listing 4 (cont.) class MyGolfball extends Golfball { public final static byte TwoPiece = 0; public final static byte ThreePiece = 1; private byte ballconstruction; public byte constuction() { return ballconstruction; public boolean equals(object obj) { if (super.equals(obj)) { MyGolfball bg = (MyGolfball)obj; // Classes equal, downcast. if (ballconstruction == gb.construction()) return true; return false; slice comparison is not permitted object equality - case studies (33) mixed-type comparison Golfball original = new Golfball("xyz", "abc",100); MyGolfball gb1 = new MyGolfball("xyz", "abc", 100, MyGolfball.TwoPiece); MyGolfball gb2 = new MyGolfball("xyz", "abc", 100, MyGolfball.ThreePiece); gb1.equals(original) // mixed-type comparison: yields false original.equals(gb2) // mixed-type comparison: yields false gb1.equals(gb2) // same-type comparison: yields false Golfball original xyz abc 100 transitive Golfball gb1 xyz abc 100 TwoPiece Golfball gb2 xyz abc 100 ThreePiece object equality - case studies (34)

evaluation slice comparison is not permitted in the sense that: mixed-type comparison is allowed, but a Golfball does never compare equal to MyGolfball type check via getclass() yields false for all attempts of mixed-type comparison only correct approach in class hierarchies of value types where equals() must be overridden object equality - case studies (35) revisiting listing 2 can we solve problem with subclass of Date? using getclass() instead of instanceof NO: leads to asymmetry superclass Date permits mixed-type comparison asymmetric behavior if subclass treats mixed-type comparison differently 8for symmetry any subclass must also allow mixed-type comparison object equality - case studies (36) 18

19 example - incorrect asymmetric equals() public class Date { // as before public boolean equals(object obj) { return obj instanceof Date && gettime() == ((Date) obj).gettime(); public class NamedDate extends Date { private String name; public boolean equals(object other) { if (other!=null && getclass() == other.getclass()) { if (!super.equals(other)) return false; return name.equals(((nameddate)other).name)); NamedDate EndOfMillenium = new NamedDate(99,11,31,"end of 2 nd Date NewYearsEve = new Date(99,11,31); millenium AC"); EndOfMillenium.equals(NewYearsEve) NewYearsEve.equals(EndOfMillenium) // slice comparison: false // slice comparison: true not symmetric object equality - case studies (37) cannot mix strategies if superclass uses instanceof test subclass cannot switch to getclass() test violates symmetry requirement if superclass uses getclass() test subclass cannot allow mixed-type comparison via instanceof symmetry requirement violated conclusion: The strategy chosen for a superclass's equals() method determines the implementation of equals() for the entire class hierarchy. All classes in the hierarchy either allow slice comparison and use instanceof or they disallow it and use getclass(). object equality - case studies (38)

wrap-up two substantially different checks for type match allow mixed-type comparison between super- and subclass objects via instanceof treat objects of different type as non-equal via getclass() implementations using getclass() are more robust than those using instanceof object equality - case studies (39) wrap-up instanceof test correct only for final classes or if at least method equals() is final in a superclass a subclass must not extend the superclass's state but can only add functionality or fields that are irrelevant for the object's state and behavior 8such as transient or static fields object equality - case studies (40) 20

wrap-up implementations using getclass() test always comply to the equals() contract correct and robust semantically very different from instanceof test prohibits comparison of sub- with superclass objects even for "trivial" class extension 8when subclass does not add any fields and would not override equals() object equality - case studies (41) agenda check for type match delegation vs. inheritance signature of equals() slice comparison yes/no correct slice comparison methods guidelines for practitioners object equality - case studies (42) 21

avoiding inheritance why not simply avoid inheritance at all? problems with non-transitive equals() only come up in class hierarchies habitually declare every new class a final class unless it is supposed to be a superclass effort of providing a robust and correct implementation of a superclass is substantially higher recommendation: Keep it simple; try out a final class before you consider implementing a non-final class. object equality - case studies (43) inheritance vs. delegation inheritance can be replaced by delegation instead of implementing new class as subclass of existing class new class is implemented as unrelated class that holds reference to object of existing class implements same methods as existing class by delegation object equality - case studies (44) 22

23 delegation - example re-implement class NamedDate does not extend Date Date field delegation public class NamedDate { private String name; private Date date; public boolean equals(object other) { if (other!=null && getclass()==other.getclass()) { if(date.equals(((nameddate)other).date) && name.equals(((nameddate)other).name)) return true; return false; public boolean before(date when) { return date.before(when); object equality - case studies (45) evaluation tedious typing required public interface must be repeated sensible and robust alternative to inheritance delegation is similar to getclass() approach NamedDate not considered compatible with Date object equality - case studies (46)

limitations delegation cannot always replace inheritance example: protected parts of superclass must be accessed by subclass Template Method pattern from GOF book example: frameworks in which superclass also serves as marker interface class hierarchy of standard exceptions (Throwable, Error, Exception, and RuntimeException) 8user-defined domain-specific exception must derive 8delegation is not an option here object equality - case studies (47) agenda check for type match delegation vs. inheritance signature of equals() slice comparison yes/no correct slice comparison methods guidelines for practitioners object equality - case studies (48) 24

25 signature of equals() all implementations of equals() in a class hierarchy have the same signature namely the one defined in class Object boolean equals(object other) reason: avoid ambiguities object equality - case studies (49) ambiguous equals() - example Object equals(object) class Super { public boolean equals(super o) { Super equals(super) class Sub extends Super { public boolean equals(object o) { error: ambiguous class Test { public static void main(string args[]) { Sub obj = new Sub(); if (obj.equals(obj)) Sub equals(object) object equality - case studies (50)

26 ambiguity analysis distance conversions Object equals(object) 2 2 candidates Super equals(super) 1 1 Sub equals(object) 0 2 ideal match Sub equals(sub) object equality - case studies (51) Barbara Liskov, "Program Development in Java", page 182 public class Point3 extends Point2 { private int z; public boolean equals(object p) { // overriding definition if (p instanceof Point3) return equals((point3)p); return super.equals(); public boolean equals(point2 p) { // overriding definition if (p instanceof Point3) return equals((point3)p); return super.equals(); public boolean equals(point3 p) { // extra definition if (p==null z!=p.z) return false; return super.equals(); object equality - case studies (52)

overriding and overloading upside can omit check for type match in one of the versions all other versions uniformly delegate to super.equals() downside all subclasses must override all overloaded versions in order to avoid ambiguities object equality - case studies (53) agenda check for type match delegation vs. inheritance signature of equals() slice comparison yes/no correct slice comparison methods guidelines for practitioners object equality - case studies (54) 27

slice comparison slice comparison is a problem in class hierarchies leads to non-transitive implementations of equals() when is it needed? when can it be avoided? object equality - case studies (55) is slice comparison sensible? Fruit comparison of Fruit slices Apple Pear Fruit is an abstraction should be an abstract class comparing Fruit part of apples and pears is meaningless object equality - case studies (56) 28

is slice comparison sensible? Person comparison of Person slices Employee Student Employee and Student are roles do not determine characteristics of a Person comparing Person part of employees and students makes sense object equality - case studies (57) is slice comparison sensible? Rectangle Square Square Rectangle comparison of Rectangle slices design violates LSP (Liskov Substitution Principle) 8 a Square cannot be used in all places where a Rectangle can be used 8 example: stretch by doubling one of the edges comparison of Square slices abuse of inheritance 8 inheritance of structure only 8 instead of inheritance of behavior highly questionable design 8 a Rectangle is not a Square object equality - case studies (58) 29

conclusion whether or not slice comparison makes sense depends on semantics of class if we want to provide slice comparison in hierarchies of value types how do we do it? object equality - case studies (59) agenda check for type match delegation vs. inheritance signature of equals() slice comparison yes/no correct slice comparison methods guidelines for practitioners object equality - case studies (60) 30

final slice comparison implement equals() as slice comparison and make final Point Point.equals() 8 compares Point slices 8 uses instanceof check to make sure that other instance has a Point part ColoredPoint ColoredPoint cannot override equals() 8 transitive: comparison is always slice comparison object equality - case studies (61) final slice comparison - example class Point { final boolean equals(object other) { if (!(other instanceof Point)) return false; class ColoredPoint extends Point { Point origin = new Point(0,0); ColoredPoint p1 = new ColoredPoint(0,0,0xFFFF); ColoredPoint p2 = new ColoredPoint(0,0,0x0000); true p1.equals(origin); origin.equals(p2); p1.equals(p2); Point.equals() object equality - case studies (62) 31

evaluation no subclass can ever define equals() again semantically correct? attributes of subclasses will never be considered for comparison in our example: color is irrelevant for comparison of (colored) points object equality - case studies (63) named slice-comparison method different names for slice comparison and full comparison Point.equals() 8 compares only Point instances 8 uses check for exact type match ColoredPoint.equals() 8 compares only ColoredPoint instances 8 no slice comparison 8 uses check for exact type match MyPoint.isSameLocationAs() 8 compares Point part of ColoredPoints 8 uses instanceof check 8 is transitive, because it considers only the Point part in all cases object equality - case studies (64) 32

named slice-comparison - example slice comparison class Point { boolean equals(object other) { if (!(other.getclass() == getclass())) return false; final boolean issamelocationas(object other) { if (!(other instanceof Point)) return false; class ColoredPoint extends Point { boolean equals(object other) { if (!super.equals(other)) return false; object equality - case studies (65) named slice-comparison - example Point origin = new Point(0,0); ColoredPoint p1 = new ColoredPoint(0,0,0xFFFF); ColoredPoint p2 = new ColoredPoint(0,0,0x0000); false: type mismatch false: different content p1.equals(origin); origin.equals(p2); p1.equals(p2); ColoredPoint.equals() Point.equals() true: same point part p1.issamelocationas(origin); origin.issamelocationas(p2); p1.issamelocationas(p2); Point.isSameLocationAs() object equality - case studies (66) 33

evaluation collections use equals() method of element type for finding elements example: 8 cannot find Point origin in collection of ColoredPoints 8 search would use Point.equals()! yields false because of type mismatch set of colored points always false Set fractal; Point origin = new Point(0,0); if (fractal.contains(origin)) object equality - case studies (67) note The next 13 slides are not contained in your handouts. object equality - case studies (68) 34

full-blown tree traversal key idea to solve the conceptual transitivity problem mixed-type comparison only succeeds if 8superclass slice is equals and 8subclass fields have default values example: Point2(1,2 1,2) is equal to Point3( but is not equal to Point3( Point3(1,2,0 1,2,0) Point3(1,2,3 1,2,3) implementation is a non-trivial task lots of issues to consider 8how do we compare objects from different branches? 8how do we avoid recursive calls to superclass equals? 8how much of a burden do we impose on future subclasses? object equality - case studies (69) principles 4 possible cases: [a] other is an instance of my class me other [b] other is an instance of a superclass of mine other me [c] other is an instance of a subclass of mine me other [d] other is none of the above (a side branch) root me other object equality - case studies (70) 35

36 [a] other is of same type just compare my fields and call my super to compare the superclass fields me other me superclass part superclass fields other superclass part subclass part my fields subclass part object equality - case studies (71) [b] other is an instance of a superclass check whether my fields have default values call my super to compare the superclass fields other me me superclass part superclass fields other superclass part subclass part my fields (default values?) object equality - case studies (72)

37 [c] other is an instance of a subclass same as [b] if roles are switched reverses the order of the operands return other.equals(this) me other me superclass part superclass fields other superclass part subclass part object equality - case studies (73) [d] other is from a side branch check for default values in both this and other traverse both branches identify superclass that they have in common straight up the hierarchy from then on root me other me superclass part superclass fields other superclass part my subclass part my fields (default values?) an entirely different subclass part object equality - case studies (74)

38 implementation - field comparison public class Point { private boolean _comparefields(object other) { if (other instanceof Point) { Point mytype = (Point)other; if (x!= mytype.x y!= mytype.y) return false; else { if (x!= 0 y!= 0) return false; return true; my class or lower; compare fields higher type or side branch; check defaults object equality - case studies (75) implementation - equals() public class Point { public boolean equals(object other) { if (other == null) return false; if (other == this) return true; null reference identical objects if (!(other instanceof Point)) return false; return _navigate(other,false); incomparable types start tree traversal object equality - case studies (76)

39 implementation - tree traversal public class ColoredPoint extends Point { protected boolean _navigate(object other, boolean reversed) { if (other instanceof ColoredPoint &&!reversed) { switch return ((ColoredPoint)other)._navigate(this,true); roles else { if(!_comparefields(other)) return false; process own fields return super._navigate(other,reversed); recursive tree traversal object equality - case studies (77) implementation - avoid infinite loop process first branch start at MySubClass_1 and ascend to MyClass (common superclass) process second branch bottom up switch roles of this and other; start at MySubSubClass; ascend to MyClass do NOT process the first branch again MySuperClass MyClass MySubClass_1 MySubClass_2 MySubSubClass object equality - case studies (78)

40 implementation - the boolean flag public class ColoredPoint extends Point { protected boolean _navigate(object other, boolean reversed) { if (other instanceof ColoredPoint &&!reversed) check value { return ((ColoredPoint)other)._navigate(this,true); flip value else { if(!_comparefields(other)) return false; return super._navigate(other,reversed); pass flag on object equality - case studies (79) boilerplate code all subclasses must use this mechanism boilerplate code trivial modification for root class trivial modification for new subclass public class Point { protected boolean _navigate(object other, boolean reversed) { if (other instanceof Point &&!reversed) { return ((Point)other)._navigate(this,true); else { if(!_comparefields(other)) return false; return true; root class no delegation to superclass object equality - case studies (80)

evaluation collections use equals() method of element type for adding elements example: 8 cannot add Point origin to collection of ColoredPoints if a origin with default color is contained in the collection no duplicates allowed in a Set 8 add would use Point.equals()! yields true because of slice comparison set of colored points will fail Set fractal; Point origin = new Point(0,0); fractal.add(origin); object equality - case studies (81) agenda check for type match delegation vs. inheritance signature of equals() slice comparison yes/no correct slice comparison methods guidelines for practitioners object equality - case studies (82) 41

check list entity type entity or value type? value type do not override equals() final class superclass or final class? super class override equals() implementation does not matter mixed-type comparison slice comparison? same-type comparison instanceof test getclass() test object equality - case studies (83) references Joshua Bloch Effective Java Addison Wesley, 2001 Klaus Kreft & Angelika Langer Secrets of equals Java Solutions, April 2002 www.cuj.com/java/articles/a19.htm?topic=java Peter Haggar Practical Java Addison Wesley, 2000 Barbara Liskov with John Guttag Program Development in Java Addison Wesley 2001 Mark Davis Liberté, Egalité, Fraternité Java Report, 1999/2000 www.macchiato.com/columns/durable5.html object equality - case studies (84) 42

43 contact info Angelika Langer Training & Mentoring Object-Oriented Software Development in C++ & Java Munich, Germany http: //www.angelikalanger.com Klaus Kreft Klaus Kreft Siemens Business Services, Munich, Germany Email: klaus.kreft@siemens.com object equality - case studies (85)