Item 10. equals
equals๋ ์ผ๋ฐ ๊ท์ฝ์ ์ง์ผ ์ฌ์ ์ํ๋ผ
equals๋ ์ฌ์ ์ํ๊ธฐ ์ฌ์ ๋ณด์ด์ง๋ง, ์๋ชป ์ฌ์ ์ํ๋ฉด ํ๋ก๊ทธ๋จ์ด ์ค๋์ํ ์ ์๋ค. ๋๋ฌธ์ ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด ์ฌ์ ์ํ์ง ์๋ ๊ฒ์ด ์ข๊ณ , ๋ค์์ ์ํฉ์ด๋ฉด ์ฌ์ ์ํ ํ์๊ฐ ์๋ค.
๊ฐ ์ธ์คํด์ค๊ฐ ๋ณธ์ง์ ์ผ๋ก ๊ณ ์ ํ๋ค.
์ธ์คํด์ค์ '๋ ผ๋ฆฌ์ ๋์น์ฑ(logical equality)'์ ๊ฒ์ฌํ ์ผ์ด ์๋ค.
์์ ํด๋์ค์์ ์ฌ์ ์ํ equals๊ฐ ํ์ ํด๋์ค์ equals์์๋ ์๋ง๊ฒ ๋์ํ๋ค.
ํด๋์ค๊ฐ private์ด๊ฑฐ๋ package-private์ด๊ณ , equals ๋ฉ์๋๋ฅผ ํธ์ถํ ์ผ์ด ์๋ค.
์ ์ํฉ์ด ์๋๋ผ ๋ ผ๋ฆฌ์ ๋์น์ฑ์ ๊ฒ์ฌํด์ผ ํ๋ค๋ฉด, ๋ค์์ ๊ท์ฝ์ ๋ฐ๋ผ ์ฌ์ ์ํด์ผ ํ๋ค.
equals ์ฌ์ ์ ๊ท์ฝ
๋ฐ์ฌ์ฑ(reflexivity): null์ด ์๋ ๋ชจ๋ ์ฐธ์กฐ ๊ฐ x์ ๋ํด, x.equals(x)๋ true๋ค.
๋์นญ์ฑ(symmetry): null์ด ์๋ ๋ชจ๋ ์ฐธ์กฐ ๊ฐ x, y์ ๋ํด, x.equals(y)๊ฐ true๋ฉด y.equals(x)๋ true๋ค.
์ถ์ด์ฑ(transitivity): null์ด ์๋ ๋ชจ๋ ์ฐธ์กฐ ๊ฐ x, y, z์ ๋ํด, x.equals(y)๊ฐ true์ด๊ณ y.equals(z)๋ true๋ฉด x.equals(z)๋ true๋ค.
์ผ๊ด์ฑ(consistency): null์ด ์๋ ๋ชจ๋ ์ฐธ์กฐ ๊ฐ x, y์ ๋ํด, x.equals(y)๋ฅผ ๋ฐ๋ณตํด์ ํธ์ถํ๋ฉด ํญ์ true๋ฅผ ๋ฐํํ๊ฑฐ๋ ํญ์ false๋ฅผ ๋ฐํํ๋ค.
null-์๋: null์ด ์๋ ๋ชจ๋ ์ฐธ์กฐ ๊ฐ x์ ๋ํด, x.equals(null)์ false๋ค.
์ผํ๋ณด๋ฉด ๋น์ฐํ ๊ท์ฝ๋ค์ด์ง๋ง, ์ค์๋ก ์ด๊ธธ ์ ์๋ ๊ท์ฝ๋ค์ด๋ค. ์์ ๊ท์ฝ๋ค์ ์ด๊ธด ์์๋ค์ ์๋์ ๊ฐ๋ค.
๋ฐ์ฌ์ฑ
์ ์์ ์ธ ์๋๊ฐ ์๋ค๋ฉด ์ด๊ธธ ์ผ์ด ์๋ค.
๋์นญ์ฑ
class CaseInsensitiveString {
private final String s;
public CaseInsensitiveString(String s) {
this.s = Objects.requireNonNull(s);
}
@Override
public boolean equals(Object o) {
if (o instanceof CaseInsensitiveString) {
return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
}
if (o instanceof String) { // ๋ฌด๋ฆฌํ๊ฒ ๋ค๋ฅธ ํ์
์ ํ์ฉํ๋ฉด์ ๋ฐ์ํ ๋ฌธ์
return s.equalsIgnoreCase((String) o);
}
return false;
}
}
class Main {
public static void main(String[] args) {
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
// ๋์นญ์ฑ ์๋ฐฐ
System.out.println(cis.equals(s)); // true
System.out.println(s.equals(cis)); // false, ๋ค๋ฅธ ํ์
์ด๊ธฐ ๋๋ฌธ์ false
}
}
์ถ์ด์ฑ
class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Point)) {
return false;
}
Point p = (Point) o;
return p.x == x && p.y == y;
}
}
class ColorPoint extends Point {
private final Color color;
public ColorPoint(int x, int y, Color color) {
super(x, y);
this.color = color;
}
@Override
public boolean equals(Object o) {
// ๊ตฌํ ๋ด์ฉ
}
}
์์ ColorPoint ํด๋์ค ๋ด์ equals ๊ตฌํ ๋ด์ฉ์ ๋ฐ๋ผ ๊ท์ฝ ์๋ฐฐ ์ฌ๋ถ๊ฐ ๊ฒฐ์ ๋๋ค. ์ฐ์ ์๋์ ๊ฐ์ด ๊ตฌํํ๊ฒ ๋๋ฉด ๋์นญ์ฑ์ด ์๋ฐฐ๋๋ค.
class ColorPoint extends Point {
// ...
@Override
public boolean equals(Object o) {
if (!(o instanceof ColorPoint)) {
return false;
}
return super.equals(o) && ((ColorPoint) o).color == color;
}
}
class Main {
public static void main(String[] args) {
Point p = new Point(1, 2);
ColorPoint cp1 = new ColorPoint(1, 2, Color.RED);
// ๋์นญ์ฑ ์๋ฐฐ
System.out.println(p.equals(cp1)); // true
System.out.println(cp1.equals(p)); // false
}
}
์ด๋ฅผ ์์ ํ์ฌ Point ํด๋์ค์ ๋ํ ๋น๊ต๋ฅผ ์ถ๊ฐํ๋ฉด ๋์นญ์ฑ์ ์ง์ผ์ง์ง๋ง, ์ถ์ด์ฑ์ด ์๋ฐฐ๋๋ค.
class ColorPoint extends Point {
// ...
@Override
public boolean equals(Object o) {
if (!(o instanceof Point)) {
return false;
}
if (!(o instanceof ColorPoint)) {
return o.equals(this);
}
return super.equals(o) && ((ColorPoint) o).color == color;
}
}
class Main {
public static void main(String[] args) {
Point p = new Point(1, 2);
ColorPoint cp1 = new ColorPoint(1, 2, Color.RED);
ColorPoint cp2 = new ColorPoint(1, 2, Color.BLUE);
// ์ถ์ด์ฑ ์๋ฐฐ
System.out.println(p.equals(cp1)); // true
System.out.println(cp1.equals(cp2)); // false
System.out.println(p.equals(cp2)); // true
}
}
๋ง์ฝ instanceof ๋์ getClass๋ฅผ ์ฌ์ฉํ๋ฉด ์ถ์ด์ฑ์ ์ง์ผ์ง์ง๋ง, ๋์นญ์ฑ์ด ์๋ฐฐ๋๋ค. ๋ํ Point์ ํ์ํด๋์ค์ธ ColorPoint๊ฐ ๋์ด์ Point๋ก์จ ์ฌ์ฉ๋ ์ ์๊ฒ ๋๋ค.(๋ฆฌ์ค์ฝํ ์นํ ์์น ์๋ฐฐ)
class ColorPoint extends Point {
// ...
@Override
public boolean equals(Object o) {
if (o == null || o.getClass() != getClass()) {
return false;
}
ColorPoint cp = (ColorPoint) o;
return super.equals(o) && cp.color == color;
}
}
class Main {
public static void main(String[] args) {
Point p = new Point(1, 2);
ColorPoint cp1 = new ColorPoint(1, 2, Color.RED);
// ๋์นญ์ฑ ์๋ฐฐ
System.out.println(p.equals(cp1)); // true
System.out.println(cp1.equals(p)); // false
}
}
์ด์ ํด๋์ค๋ฅผ ํ์ฅํ๋ ๊ฒฝ์ฐ์๋ equals ๊ท์ฝ์ ์งํค๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๋ค๊ณ ๋ณผ ์ ์์ง๋ง, ์ฐํํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
class ColorPoint {
private final Point point;
private final Color color;
public ColorPoint(int x, int y, Color color) {
point = new Point(x, y);
this.color = Objects.requireNonNull(color);
}
public Point asPoint() {
return point;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ColorPoint)) {
return false;
}
ColorPoint cp = (ColorPoint) o;
return cp.point.equals(point) && cp.color == color;
}
}
์ ๋ฐฉ๋ฒ์ผ๋ก equals ๊ท์ฝ์ ์งํฌ ์ ์์ง๋ง, ColorPoint๋ฅผ Point์๋ ๋์ด์ ์์ ๊ด๊ณ๋ ์๋๊ฒ ๋๋ค.
์ผ๊ด์ฑ
equals์ ํ์๋ฐ ์ ๋ขฐํ ์ ์๋ ์์์ด ๋ผ์ด๋ค์ง ์๋๋ก ํด์ผ ํ๋ค.
null-์๋
instanceof ์ฐ์ฐ์๋ก ์ ๋ ฅ ๋งค๊ฐ๋ณ์๊ฐ ์ฌ๋ฐ๋ฅธ ํ์ ์ธ์ง ํ์ธํ๋ฉด ๋ช ์์ ์ผ๋ก null ๊ฒ์ฌ๋ฅผ ํ ํ์๊ฐ ์๋ค. ์ ๋ ฅ์ด null์ด๋ฉด ํ์ ํ์ธ ๋จ๊ณ์์ false๋ฅผ ๋ฐํํ๋ฏ๋ก null ๊ฒ์ฌ๋ฅผ ๋ช ์์ ์ผ๋ก ํ์ง ์์๋ ๋๋ค.
class Test {
// ...
// ๋ช
์์ null ๊ฒ์ฌ
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
// ...
}
// ๋ฌต์์ null ๊ฒ์ฌ
@Override
public boolean equals(Object o) {
if (!(o instanceof Test)) {
return false;
}
// ...
}
}
equals ๋ฉ์๋ ๊ตฌํ์ ์ฃผ์์ฌํญ
== ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด ์ ๋ ฅ์ด ์๊ธฐ ์์ ์ ์ฐธ์กฐ์ธ์ง ํ์ธ
์๊ธฐ ์์ ์ด๋ฉด true๋ฅผ ๋ฐํ
๋จ์ํ ์ฑ๋ฅ ์ต์ ํ์ฉ์ผ๋ก ๋น๊ต ์์ ์ด ๋ณต์กํ ์ํฉ์ผ ๋ ์ข์
instanceof ์ฐ์ฐ์๋ก ์ ๋ ฅ์ด ์ฌ๋ฐ๋ฅธ ํ์ ์ธ์ง ํ์ธ
๊ฐ๋ ํด๋น ํด๋์ค๊ฐ ๊ตฌํํ ํน์ ์ธํฐํ์ด์ค๋ฅผ ๋น๊ตํ ์๋ ์์
์ด๋ฐ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ํด๋์ค๋ผ๋ฉด equals์์ (ํด๋์ค๊ฐ ์๋) ํด๋น ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํด์ผํจ
์ ๋ ฅ์ ์ฌ๋ฐ๋ฅธ ํ์ ์ผ๋ก ํ๋ณํ
2๋ฒ์์ instanceof ์ฐ์ฐ์๋ก ์ ๋ ฅ์ด ์ฌ๋ฐ๋ฅธ ํ์ ์ธ์ง ๊ฒ์ฌ ํ๊ธฐ ๋๋ฌธ์ ์ด ๋จ๊ณ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์์
์ ๋ ฅ ๊ฐ์ฒด์ ์๊ธฐ ์์ ์ ๋์๋๋ 'ํต์ฌ' ํ๋๋ค์ด ๋ชจ๋ ์ผ์นํ๋์ง ํ๋์ฉ ๊ฒ์ฌ
๋ชจ๋ ์ผ์นํด์ผ true๋ฅผ ๋ฐํํ๋๋ก ๊ตฌํ
๊ธฐ๋ณธ ํ์ ์ ==๋ก ๋น๊ตํ๊ณ ์ฐธ์กฐํ์ ์ equals๋ก ๋น๊ต
float, double ํ๋๋ ์ ์ ๋ฉ์๋ Float.compare(float, float)์ Double.compare(double, double)๋ก ๋น๊ต
Float.equals(float)๋ Double.equals(double)๋ ์คํ ๋ฐ์ฑ์ ์๋ฐํด ์ฑ๋ฅ์ ์ข์ง ์์
๋ฐฐ์ด ํ๋๋ ์์ ๊ฐ๊ฐ์ ์ง์นจ๋๋ก ๋น๊ต
๋ชจ๋๊ฐ ํต์ฌ ํ๋๋ผ๋ฉด Arrays.equals()๋ฅผ ์ฌ์ฉ
NullPointException ๋ฐ์์ ์๋ฐฉํ๊ธฐ ์ํด Object.equals(object, object)๋ก ๋น๊ต
ํ๋์ ๋น๊ต ์์๋ฅผ ์์ ๋น์ฉ์ด ๋๋ ํ๋๋ถํฐ ํฐ ๋น์ฉ์ด ๋๋ ํ๋ ์์ผ๋ก ๋น๊ต
eqauls๋ฅผ ์ฌ์ ์ํ ๋ hashCode๋ ๋ฐ๋์ ์ฌ์ ์
Last updated
Was this helpful?