# 物件相等性

String s1 = new String("Java");
String s2 = new String("Java");
System.out.println(s1 == s2);       // 顯示 false
System.out.println(s1.equals(s2));  // 顯示 true

public boolean equals(Object obj) {
return (this == obj);
}

``public class Point {    public final int x;    public final int y;    public Point(int x, int y) {        this.x = x;        this.y = y;    }    public boolean equals(Point that) {        return this.x == that.x && this.y == that.y;    }}``

Point p1 = new Point(1, 1);
Point p2 = new Point(1, 1);
System.out.println(p1.equals(p2));  // 顯示 true

Point p1 = new Point(1, 1);
Point p2 = new Point(1, 1);
Set<Point> pSet = new HashSet<Point>();
System.out.println(pSet.contains(p2));    // 顯示 false

Object p1 = new Point(1, 1);
Point p2 = new Point(1, 1);
System.out.println(p1.equals(p2));  // 顯示 false

p1是Object宣告，看不到Point中的equals()，所以就使用Object本身的equals()，結果當然是false。

``public class Point {    public final int x;    public final int y;    public Point(int x, int y) {        this.x = x;        this.y = y;    }    @Override    public boolean equals(Object that) {        if(that instanceof Point) {            Point p = (Point) that;            return this.x == p.x && this.y == p.y;        }        return false;    }}``

Object p1 = new Point(1, 1);
Point p2 = new Point(1, 1);
System.out.println(p1.equals(p2));  // 顯示 true

Point p1 = new Point(1, 1);
Point p2 = new Point(1, 1);
Set<Point> pSet = new HashSet<Point>();
System.out.println(pSet.contains(p2));    // 可能顯示 false

• 在同一個應用程式執行期間，對同一物件呼叫 hashCode()方法，必須回傳相同的整數結果。
• 如果兩個物件使用equals(Object)測試結果為相等, 則這兩個物件呼叫hashCode()時，必須獲得相同的整數結果。
• 如果兩個物件使用equals(Object)測試結果為不相等, 則這兩個物件呼叫hashCode()時，可以獲得不同的整數結果。

``public class Point {    public final int x;    public final int y;    public Point(int x, int y) {        this.x = x;        this.y = y;    }    @Override    public boolean equals(Object that) {        if(that instanceof Point) {            Point p = (Point) that;            return this.x == p.x && this.y == p.y;        }        return false;    }    @Override    public int hashCode() {        return 41 * (41 + x) + y;    }}``

Point p1 = new Point(1, 1);
Point p2 = new Point(1, 1);
Set<Point> pSet = new HashSet<Point>();
System.out.println(pSet.contains(p2));    // 顯示 true

Point p1 = new Point(1, 1);
Set<Point> pSet = new HashSet<Point>();
System.out.println(pSet.contains(p1));  // 顯示 true
p1.x = 2;
System.out.println(pSet.contains(p1));  // 顯示 false

• 反身性（Reflexive）：x.equals(x)的結果要是true。
• 對稱性（Symmetric）：x.equals(y)與y.equals(x)的結果必須相同。
• 傳遞性（Transitive）：x.equals(y)、y.equals(z)的結果都是true，則x.equals(z)的結果也必須是true。
• 一致性（Consistent）：同一個執行期間，對x.equals(y)的多次呼叫，結果必須相同。
• 對任何非null的x，x.equals(null)必須傳回false。

``public class Point3D extends Point {    public final int z;    public Point3D(int x, int y, int z) {        super(x, y);        this.z = z;    }    @Override    public boolean equals(Object that) {        if(that instanceof Point3D) {            Point3D p = (Point3D) that;            return super.equals(p) && this.z == p.z;        }        return false;    }}``

Point p1 = new Point(1, 1);
Point p2 = new Point3D(1, 1, 1);
System.out.println(p1.equals(p2));   // 顯示 true
System.out.println(p2.equals(p1));   // 顯示 false

``public class Point3D extends Point {    public final int z;    public Point3D(int x, int y, int z) {        super(x, y);        this.z = z;    }    @Override    public boolean equals(Object that) {        if(that instanceof Point3D) {            Point3D p = (Point3D) that;            return super.equals(p) && this.z == p.z;        }        if(that instanceof Point) {            return that.equals(this);        }        return false;    }}``

Point p1 = new Point(1, 1);
Point p2 = new Point3D(1, 1, 1);
Point p3 = new Point3D(1, 1, 2);
System.out.println(p2.equals(p1));  // 顯示 true
System.out.println(p1.equals(p3));  // 顯示 true
System.out.println(p2.equals(p3));  // 顯示 false

p2等於p1，p1等於p3，但p2不等於p3，這違反傳遞性合約。問題點在於，2D的點並沒有z軸資訊，無論如何也沒辦法滿足傳遞性了。

``public class Point {    public final int x;    public final int y;    public Point(int x, int y) {        this.x = x;        this.y = y;    }    @Override    public boolean equals(Object that) {        if(that instanceof Point) {            Point p = (Point) that;            return this.getClass() == p.getClass() &&                   this.x == p.x &&                    this.y == p.y;        }        return false;    }    @Override    public int hashCode() {        return 41 * (41 + x) + y;    }}``

``public class Point3D extends Point {    public final int z;    public Point3D(int x, int y, int z) {        super(x, y);        this.z = z;    }    @Override    public boolean equals(Object that) {        if(that instanceof Point3D) {            Point3D p = (Point3D) that;            return super.equals(p) && this.z == p.z;        }        return false;    }}``

Point p1 = new Point(1, 1);
Point p2 = new Point(1, 1) {
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
};
Set<Point> pSet = new HashSet<Point>();
System.out.println(pSet.contains(p1));   // 顯示 true
System.out.println(pSet.contains(p2));   // 顯示 false，但你想顯示 true

``public class Point {    public final int x;    public final int y;    public Point(int x, int y) {        this.x = x;        this.y = y;    }    @Override    public boolean equals(Object that) {        if(that instanceof Point) {            Point p = (Point) that;            return p.canEquals(this) &&                   this.x == p.x &&                    this.y == p.y;        }        return false;    }    public boolean canEquals(Object that) {        return that instanceof Point;    }    @Override    public int hashCode() {        return 41 * (41 + x) + y;    }}``

``public class Point3D extends Point {    public final int z;    public Point3D(int x, int y, int z) {        super(x, y);        this.z = z;    }    @Override    public boolean equals(Object that) {        if(that instanceof Point3D) {            Point3D p = (Point3D) that;            return p.canEquals(this) &&                    super.equals(p) && this.z == p.z;        }        return false;    }    @Override    public boolean canEquals(Object that) {        return that instanceof Point3D;    }    @Override    public int hashCode() {        return 41 * super.hashCode() + z;    }}``

Point p1 = new Point(1, 1);
Point p2 = new Point(1, 1) {
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
};
Point p3 = new Point3D(1, 1, 1);
Set<Point> pSet = new HashSet<Point>();