001package algs34;
002import stdlib.*;
003import java.util.HashSet;
004/* ***********************************************************************
005 *  Compilation:  javac PhoneNumber.java
006 *  Execution:    java PhoneNumber
007 *  Dependencies:
008 *
009 *  Immutable data type for US phone numbers, but with a broken
010 *  overloaded implementation of equals(). By implementing equals()
011 *  with the signature
012 *
013 *       public boolean equals(PhoneNumber that)
014 *
015 *  we do not override the equals() method inherited from Object.
016 *  This causes unexpected behavior when used with java.util.HashSet.
017 *
018 *  DO NOT USE THIS CLASS
019 *
020 *************************************************************************/
021
022public final class XPhoneNumberOverload {
023        private final int area;   // area code (3 digits)
024        private final int exch;   // exchange  (3 digits)
025        private final int ext;    // extension (4 digits)
026
027        public XPhoneNumberOverload(int area, int exch, int ext) {
028                this.area = area;
029                this.exch = exch;
030                this.ext  = ext;
031        }
032
033        // overloaded equals - don't do this
034        public boolean equals(XPhoneNumberOverload that) {
035                return (this.area == that.area) && (this.exch == that.exch) && (this.ext == that.ext);
036        }
037
038        // satisfies the hashCode contract
039        public int hashCode() {
040                int h = 17;
041                h = ext + 31 * h;
042                h = exch + 31 * h;
043                h = area + 31 * h;
044                return h;
045        }
046
047        // 0 for padding with leading 0s
048        public String toString() {
049                return String.format("(%03d) %03d-%04d", area, exch, ext);
050        }
051
052        public static void main(String[] args) {
053                XPhoneNumberOverload a = new XPhoneNumberOverload(609, 258, 4455);
054                XPhoneNumberOverload b = new XPhoneNumberOverload(609, 876, 5309);
055                XPhoneNumberOverload c = new XPhoneNumberOverload(609, 003, 5309);
056                XPhoneNumberOverload d = new XPhoneNumberOverload(215, 876, 5309);
057                XPhoneNumberOverload e = new XPhoneNumberOverload(609, 876, 5309);
058                Object o = e;
059                StdOut.format("a = %s [hashcode=%d]\n", a, a.hashCode ());
060                StdOut.format("b = %s [hashcode=%d]\n", b, b.hashCode ());
061                StdOut.format("c = %s [hashcode=%d]\n", c, c.hashCode ());
062                StdOut.format("d = %s [hashcode=%d]\n", d, d.hashCode ());
063                StdOut.format("e = %s [hashcode=%d]\n", e, e.hashCode ());
064
065                // show broken behavior when you use covariant equals with a Set
066                HashSet<XPhoneNumberOverload> set = new HashSet<>();
067                set.add(a);
068                set.add(b);
069                set.add(c);
070                StdOut.println("Added a, b, and c");
071                StdOut.println("contains a:  " + set.contains(a));
072                StdOut.println("contains b:  " + set.contains(b));
073                StdOut.println("contains c:  " + set.contains(c));
074                StdOut.println("contains d:  " + set.contains(d));
075                StdOut.println("***contains e:  " + set.contains(e));  // not in set, but it should be!
076                StdOut.println("b == e:      " + (b == e));
077                StdOut.println("b.equals(e): " + (b.equals(e)));
078                StdOut.println("o == e:      " + (o == e));
079                StdOut.println("b.equals(o): " + (b.equals(o)));
080        }
081
082}
083