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