๐ ๋ชฉ์ฐจ.
1. ์ฑํฐ
.์์ดํ 10 - equals๋ ์ผ๋ฐ ๊ท์ฝ์ ์ง์ผ ์ฌ์ ์ ํ๋ผ
.์์ดํ 11 - equals๋ฅผ ์ฌ์ ์ํ๋ ค๊ฑฐ๋ hashCode๋ ์ฌ์ ์ํ๋ผ
.์์ดํ 12 - toString์ ํญ์ ์ฌ์ ์ํ๋ผ
.์์ดํ 13 - clone ์ฌ์ ์๋ ์ฃผ์ํด์ ์งํํ๋ผ
.์์ดํ 14 - Comparable์ ๊ตฌํํ ์ง ๊ณ ๋ คํ๋ผ.
โ๏ธ ๋ด์ฉ.
3. ๋ชจ๋ ๊ฐ์ฒด์ ๊ณตํต ๋ฉ์๋
Object๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์๋ ๊ตฌ์ฒด ํด๋์ค์ด์ง๋ง. ๊ธฐ๋ณธ์ ์ผ๋ก๋ ์์ํด์ ์ฌ์ฉํ๋๋ก ์ค๊ณ๋์๋ค.
Object์์final์ด ์๋ ๋ฉ์๋(equals, hashCode, toString, clone, finalize)๋ ๋ชจ๋ ์ฌ์ ์๋ฅผ ์ผ๋์ ๋๊ณ ์ค๊ณ๋ ๊ฒ์ด๋ผ ์ฌ์ ์ ์ ์ง์ผ์ผ ํ๋ ์ผ๋ฐ ๊ท์ฝ์ด ๋ช ํํ ์ ์๋์ด ์๋ค.
์ด๋ฒ ์ฅ์์๋ final์ด ์๋ Object ๋ฉ์๋๋ค์ ์ธ์ ์ด๋ป๊ฒ ์ฌ์ ์ํด์ผ ํ๋์ง๋ฅผ ๋ค๋ฃฌ๋ค.
- final ์ 2์ฅ Item 8์์ ๋ค๋ค์ผ๋ฏ๋ก ์ธ๊ธํ์ง ์๋๋ค.
- Comparable.compareTo์ ๊ฒฝ์ฐ Object์ ๋ฉ์๋๋ ์๋์ง๋ง ์ด ๋น์ทํ์ฌ ์ด๋ฒ ์ฅ์์ ๊ฐ์ด ๋ค๋ฃฌ๋ค.
.์์ดํ 10 - equals๋ ์ผ๋ฐ ๊ท์ฝ์ ์ง์ผ ์ฌ์ ์ ํ๋ผ
equals ๋ฉ์๋๋ ์ฌ์ ์ํ๊ธฐ ์ฌ์ ๋ณด์ด์ง๋ง ๊ณณ๊ณณ์ ํจ์ ์ด ๋์ฌ๋ฆฌ๊ณ ์๋ค.
๋ค์ ์ด๊ฑฐ ์ํฉ ์ค ํ๊ฐ์ง๋ผ๋ ํด๋นํ๋ค๋ฉด ์ฌ์ ์ํ์ง ์๋ ๊ฒ์ด ์ข๋ค.
1. ๊ฐ ์ธ์คํด์ค๊ฐ ๋ณธ์ง์ ์ผ๋ก ๊ณ ์ ํ๋ค.
- ๊ฐ์ ํํํ๋ ๊ฒ ์๋๋ผ ๋์ํ๋ ๊ฐ์ฒด๋ฅผ ํํํ๋ ํด๋์ค
- Thread๊ฐ ์ข์ ์๋ก, Object์ equals ๋ฉ์๋๋ ์ด๋ฌํ ํด๋์ค์ ๋ฑ ๋ง๊ฒ ๊ตฌํ๋์ด ์๋ค.
2. ์ธ์คํด์ค์ '๋ ผ๋ฆฌ์ ๋์น์ฑ'์ ๊ฒ์ฌํ ์ผ์ด ์๋ค.
- ํด๋ผ์ด์ธํธ๊ฐ ๋ ผ๋ฆฌ์ ๋์น์ฑ์ ์ํ์ง ์๊ฑฐ๋ ์ ์ด์ ํ์ํ์ง ์๋ค๊ณ ํ๋จํ ๊ฒฝ์ฐ Object์ ๊ธฐ๋ณธ equals๋ก๋ง ํด๊ฒฐํ๋ค.
3. ์์ ํด๋์ค์์ ์ฌ์ ์ํ equals๊ฐ ํ์ ํด๋์ค์๋ ๋ฑ ๋ค์ด๋ง๋๋ค.
- ์๋ก ๋๋ถ๋ถ์ Set ๊ตฌํ์ฒด๋ AbstractSet์ด ๊ตฌํํ equals๋ฅผ ์์๋ฐ์ ์ฐ๊ณ , List ๊ตฌํ์ฒด๋ค์ AbstractList๋ก๋ถํฐ, Map ๊ตฌํ์ฒด๋ค์ AbstractMap์ผ๋ก๋ถํฐ ์์๋ฐ์ ๊ทธ๋๋ก ์ด๋ค.
4. ํด๋์ค๊ฐ private์ด๊ฑฐ๋ package-private(default)์ด๊ณ equals ๋ฉ์๋๋ฅผ ํธ์ถํ ์ผ์ด ์๋ค.
- ํธ์ถํ ์ผ์ด ์๊ณ ํน์ฌ๋ ์ค์๋ก๋ผ๋ equals๋ฅผ ํธ์ถํ์ง ๋ชปํ๊ฒ ๋ง๊ณ ์ถ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํด ๋์
public class NonEquals {
@Override
public boolean equals(Object obj) {
throw new AssertionError();
}
}
๊ทธ๋ ๋ค๋ฉด equals๋ฅผ ์ฌ์ ์ํด์ผ ํ ๋๋ ์ธ์ ์ธ๊ฐ?
- ๊ฐ์ฒด ์๋ณ์ฑ(๋ ๊ฐ์ฒด๊ฐ ๋ฌผ๋ฆฌ์ ์ผ๋ก ๊ฐ์๊ฐ)์ด ์๋๋ผ ๋ ผ๋ฆฌ์ ๋์น์ฑ์ ํ์ธํด์ผ ํ๋๋ฐ, ์์ ํด๋์ค์ equals๊ฐ ๋ ผ๋ฆฌ์ ๋์น์ฑ์ ๋น๊ตํ๋๋ก ์ฌ์ ์ ๋์ง ์์์ ๋์ด๋ค. ์ฃผ๋ก Integer์ String์ฒ๋ผ ๊ฐ์ ํํํ๋ ํด๋์ค์ด๋ค. ๋ ๊ฐ ๊ฐ์ฒด๋ฅผ equals๋ก ๋น๊ตํ๋ ํ๋ก๊ทธ๋๋จธ๋ ๊ฐ์ฒด๊ฐ ๊ฐ์์ง๊ฐ ์๋๋ผ ๊ฐ์ด ๊ฐ์์ง ์๊ณ ์ถ์ด ํ ๊ฒ์ด๋ค.
๊ฐ ํด๋์ค์ฌ๋ ์ธ์คํด์ค๊ฐ ๋ ์ด์ ๋ง๋ค์ด์ง์ง ์์์ ๋ณด์ฅํ๋ ์ธ์คํด์ค ํต์ ํด๋์ค(์์ดํ 1)๋ผ๋ฉด equals๋ฅผ ์ฌ์ ์ํ์ง ์์๋ ๋๋ค. Enum(์์ดํ 34)๋ ์ฌ๊ธฐ์ ํด๋นํ๋ค. ์ด๋ฐ ํด๋์ค์์๋ ์ด์ฐจํผ ๋ ผ๋ฆฌ์ ์ผ๋ก ๊ฐ์ ์ธ์คํด์ค๊ฐ 2๊ฐ ์ด์ ๋ง๋ค์ด์ง์ง ์์ผ๋ ๋ ผ๋ฆฌ์ ๋์น์ฑ๊ณผ ๊ฐ์ฒด ์๋ณ์ฑ์ด ์ฌ์ค์ ๋๊ฐ์ ์๋ฏธ๊ฐ ๋๋ค. ๋ฐ๋ผ์ Object์ equals๊ฐ ๋ ผ๋ฆฌ์ ๋์น์ฑ๊น์ง ํ์ธํด ์ค๋ค๊ณ ๋ณผ ์ ์๋ค.
equals ๋ฉ์๋๋ฅผ ์ฌ์ ์ ํ ๋๋ ๋ฐ๋์ ์ผ๋ฐ ๊ท์ฝ์ ๋ฐ๋ผ์ผ ํ๋ค. ๋ค์์ object ๋ช ์ธ์ ์ ํ ๊ท์ฝ์ด๋ค.
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์ ๋ํด, xequals(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 ๋ค.
๋ชจ๋ ๊ฐ์ฒด ์งํฅ ์ธ์ด์ ๋์น ๊ด๊ณ์์ ๋ฐ์ํ๋ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๊ฐ ์๋ค.
- ๊ตฌ์ฒด ํด๋์ค๋ฅผ ํ์ฅํด ์๋ก์ด ๊ฐ์ ์ถ๊ฐํ๋ฉด์ equals ๊ท์ฝ์ ๋ง์กฑ์ํฌ ๋ฐฉ๋ฒ์ ์กด์ฌํ์ง ์๋๋ค. ๊ฐ์ฒด ์งํฅ์ ์ถ์ํ์ ์ด์ ์ ํฌ๊ธฐํ์ง ์๋ ํ์ ๋ง์ด๋ค.
์ด ๋ง์ ์ผํ, equals์์ instanceof ๊ฒ์ฌ๋ฅผ getClass ๊ฒ์ฌ๋ก ๋ฐ๊พธ๋ฉด ๊ท์ฝ๋ ์งํค๊ณ ๊ฐ๋ ์ถ๊ฐํ๋ฉด์ ๊ตฌ์ฒด ํด๋์ค๋ฅผ ์์ํ ์ ์๋ค๋ ๋ป์ผ๋ก ๋ค๋ฆฐ๋ค.
- ๋ฆฌ์ค์ฝํ ์นํ ์์น ์๋ฐฐ
public class Point {
final int x;
final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Point))
return false;
Point p = (Point) obj;
return p.x == x && p.y == y;
}
}
public class CounterPoint extends Point {
public CounterPoint(int x, int y) {
super(x, y);
}
@Override
public boolean equals(Object obj) {
// ๋ฆฌ์ค์ฝํ ์นํ ์์น ์๋ฐฐ
if (obj == null || obj.getClass() != getClass())
return false;
Point p = (Point) obj;
return p.x == x && p.y == y;
}
}
๊ตฌ์ฒด ํด๋์ค์ ํ์ ํด๋์ค์์ ๊ฐ์ ์ถ๊ฐํ ๋ฐฉ๋ฒ์ ์์ง๋ง ๊ด์ฐฎ์ ์ฐํ ๋ฐฉ๋ฒ์ด ์๋ค. '์์ ๋์ ์ปดํฌ์ง์ ์ ์ฌ์ฉํ๋ผ'๋ ์์ดํ 18์ ์กฐ์ธ์ ๋ฐ๋ฅด๋ฉด ๋๋ค.
Point๋ฅผ ์์ํ๋ ๋์ Point๋ฅผ CounterPoint์ private ํ๋๋ก ๋๊ณ , CounterPoint์ ๊ฐ์ ์์น์ ์ผ๋ฐ Point๋ฅผ ๋ฐํํ๋ ๋ทฐ(view) ๋ฉ์๋(์์ดํ 6)๋ฅผ public์ผ๋ก ์ถ๊ฐํ๋ ์์ด๋ค.
- equals ๊ท์ฝ์ ์งํค๋ฉฐ ๊ฐ ์ถ๊ฐ
public class CounterPoint {
private final Point point;
private final int x;
private final int y;
public CounterPoint(int x, int y) {
this.x = x;
this.y = y;
point = new Point(x, y);
}
/**
* Point ๋ทฐ ๋ฐํ
*/
public Point asPoint(){
return point;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof CounterPoint))
return false;
CounterPoint cp = (CounterPoint) obj;
return cp.point.equals(point);
}
}
ํด๋์ค๊ฐ ๋ถ๋ณ์ด๋ ๊ฐ๋ณ์ด๋ equals ํ๋จ์ ์ ๋ขฐํ ์ ์๋ ์์์ด ๋ผ์ด๋ค๊ฒ ํด์๋ ์๋๋ค.
์๋ก java.net.URL์ equals๋ ์ฃผ์ด์ง URL๊ณผ ๋งคํ๋ ํธ์คํธ์ IP ์ฃผ์๋ฅผ ์ด์ฉํด ๋น๊ตํ๋ค. ํธ์คํธ ์ด๋ฆ์ IP ์ฃผ์๋ก ๋ฐ๊พธ๋ ค๋ฉด ๋คํธ์ํฌ๋ฅผ ํตํด์ผ ํ๋๋ฐ, ๊ทธ ๊ฒฐ๊ณผ๊ฐ ํญ์ ๊ฐ๋ค๊ณ ๋ณด์ฅํ ์ ์๋ค. ์ด๋ URL์ equals๊ฐ ์ผ๋ฐ ๊ท์ฝ์ ์ด๊ธฐ๊ฒ ํ๊ณ , ์ค๋ฌด์์๋ ์ข ์ข ๋ฌธ์ ๋ฅผ ์ผ์ผํจ๋ค.
public boolean equals(Object var1) {
if (!(var1 instanceof URL)) {
return false;
} else {
URL var2 = (URL)var1;
return this.handler.equals(this, var2); // ๋ฌธ์ ์
}
}
// ๋ฌธ์ ์
protected boolean equals(URL var1, URL var2) {
String var3 = var1.getRef();
String var4 = var2.getRef();
return (var3 == var4 || var3 != null && var3.equals(var4)) && this.sameFile(var1, var2);
}
์ด๋ฐ ๋ฌธ์ ๋ฅผ ํผํ๋ ค๋ฉด equals๋ ํญ์ ๋ฉ๋ชจ๋ฆฌ์ ์กด์ฌํ๋ ๊ฐ์ฒด๋ง์ ์ฌ์ฉํ ๊ฒฐ์ ์ ๊ณ์ฐ๋ง ์ํํด์ผ ํ๋ค.
๋ง์ง๋ง ์๊ฑด์ ๊ณต์ ์ด๋ฆ์ด ์์ผ๋ฏ๋ก 'null-์๋'์ผ๋ก ๋ถ๋ฅธ๋ค.
์ด๋ฆ์ฒ๋ผ ๋ชจ๋ ๊ฐ์ฒด๊ฐ null๊ณผ ๊ฐ์ง ์์์ผ ํ๋ค. ๋ช ์์ null ๊ฒ์ฌ๋ ํ์ ์๋ค.
@Override
public boolean equals(Object obj) {
// ํ์ ์๋ค.
if(obj == null)
return false;
return super.equals(obj);
}
- ๋ฌต์์ Null ๊ฒ์ฌ๋ก instanceof ์ฐ์ฐ์๋ก ์ฌ๋ฐ๋ฅธ ํ์ ์ธ์ง ๊ฒ์ฌํ์.
@Override
public boolean equals(Object obj) {
// ๋ฌต์์ Null ๊ฒ์ฌ
if(!(obj instanceof MyType))
return false;
MyType myType = (MyType) obj;
return super.equals(myType);
}
์ง๊ธ๊น์ง๋ฅผ ์ข ํฉํด์ ์์ง์ equals ๋ฉ์๋ ๊ตฌํ ๋ฐฉ๋ฒ์ ๋จ๊ณ๋ณ๋ก ์ ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
1. == ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด ์ ๋ ฅ์ด ์๊ธฐ ์์ ์ ์ฐธ์กฐ์ธ์ง ํ์ธํ๋ค.
- ์๊ธฐ ์์ ์ด๋ฉด true๋ฅผ ๋ฐํํ์ฌ. ๋จ์ํ ์ฑ๋ฅ ์ต์ ํ์ฉ์ผ๋ก, ๋น๊ต ์์ ์ด ๋ณต์กํ ์ํฉ์ผ ๋ ๊ฐ์ด์น๋ฅผ ํ๋ค.
2. instanceof ์ฐ์ฐ์๋ก ์ ๋ ฅ์ด ์ฌ๋ฐ๋ฅธ ํ์ ์ธ์ง ํ์ธํ๋ค.
- ๊ทธ๋ ์ง ์๋ค๋ฉด false๋ฅผ ๋ฐํํ๋ค. ์ด๋์ ์ฌ๋ฐ๋ฅธ ํ์ ์ equals๊ฐ ์ ์๋ ํด๋์ค์ธ ๊ฒ์ด ๋ณดํต์ด์ง๋ง, ๊ฐ๋ ๊ทธ ํด๋์ค๊ฐ ๊ตฌํํ ํน์ ์ธํฐํ์ด์ค๊ฐ ๋ ์ ๋ ์๋ค. ์ด๋ค ์ธํฐํ์ด์ค๋ ์์ ์ ๊ตฌํํ (์๋ก ๋ค๋ฅธ) ํด๋์ค๋ผ๋ฆฌ ๋น๊ตํ ์ ์๋๋ก equals ๊ท์ฝ์ ์์ ํ๊ธฐ๋ ํ๋ค. ์ด๋ฐ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ํด๋์ค๋ผ๋ฉด equals์์ (ํด๋์ค๊ฐ ์๋) ํด๋น ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค. Set, List, Map, Map.Entry ๋ฑ์ ์ปฌ๋ ์ ์ธํฐํ์ด์ค๋ค์ด ์ฌ๊ธฐ์ ํด๋นํ๋ค.
public boolean equals(Object o) {
if (!(o instanceof Map.Entry)) {
return false;
} else {
Map.Entry<?, ?> e = (Map.Entry)o;
// ๋ค๋ฅธ ๊ตฌํ์ฒด ํ์ธ
return AbstractMap.eq(this.key, e.getKey()) && AbstractMap.eq(this.value, e.getValue());
}
}
3. ์ ๋ ฅ์ ์ฌ๋ฐ๋ฅธ ํ์ ์ผ๋ก ํ๋ณํํ๋ค.
- ์์ 2๋ฒ์์ instanceof ๊ฒ์ฌ๋ฅผ ํ๊ธฐ ๋๋ฌธ์ ์ด ๋จ๊ณ๋ 100% ์ฑ๊ณตํ๋ค.
4. ์ ๋ ฅ ๊ฐ์ฒด์ ์๊ธฐ ์์ ์ ๋์๋๋ 'ํต์ฌ'ํ๋๋ค์ด ๋ชจ๋ ์ผ์นํ๋์ง ํ๋์ฉ ๊ฒ์ฌํ๋ค.
- ๋ชจ๋ ํ๋๊ฐ ์ผ์นํ๋ฉด true, ํ๋๋ผ๋ ๋ค๋ฅด๋ฉด false๋ฅผ ๋ฐํํ๋ค. 2๋จ๊ณ์์ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ ๋ ฅ์ ํ๋ ๊ฐ์ ๊ฐ์ ธ์ฌ ๋๋ ๊ทธ ์ธํฐํ์ด์ค์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค. ํ์ ์ด ํด๋์ค๋ผ๋ฉด (์ ๊ทผ ๊ถํ์ ๋ฐ๋ผ) ํด๋น ํ๋์ ์ง์ ์ ๊ทผํ ์๋ ์๋ค.
์ด๋ค ํ๋๋ฅผ ๋จผ์ ๋น๊ตํ๋๋๊ฐ equals์ ์ฑ๋ฅ์ ์ข์ฐํ๊ธฐ๋ ํ๋ค. ์ต์์ ์ฑ๋ฅ์ ๋ฐ๋๋ค๋ฉด ๋ค๋ฅผ ๊ฐ๋ฅ์ฑ์ด ๋ ํฌ๊ฑฐ๋ ๋น๊ตํ๋ ๋น์ฉ์ด ์ผ ํ๋๋ฅผ ๋น๊ตํ์. ๋๊ธฐํ์ฉ ๋ฝ(lock) ํ๋ ๊ฐ์ด ๊ฐ์ฒด์ ๋ ผ๋ฆฌ์ ์ํ์ ๊ด๋ จ ์๋ ํ๋๋ ๋น๊ตํ๋ฉด ์ ๋๋ค.
equals๋ฅผ ๋ค ๊ตฌํํ๋ค๋ฉด ์ธ ๊ฐ์ง๋ง ์๋ฌธํด ๋ณด์. ๋์นญ์ ์ธ๊ฐ? ์ถ์ด์ฑ์ด ์๋๊ฐ? ์ผ๊ด์ ์ธ๊ฐ?
- ์๋ฌธ์์ ๋๋ด์ง ๋ง๊ณ ๋จ์ ํ ์คํธ๋ฅผ ์์ฑํด ๋๋ ค๋ณด์. ๋จ, equals ๋ฉ์๋๋ฅผ AutoValue(Google ํ๋ ์์ํฌ, ๋ค๋ฅธ ์๋ก Lombok)๋ฅผ ์ด์ฉํด ์์ฑํ๋ค๋ฉด ํ ์คํธ๋ฅผ ์๋ตํด๋ ์์ฌํ ์ ์๋ค. ๋ฌผ๋ก ๋๋จธ์ง ์๊ฑด์ธ ๋ฐ์ฌ์ฑ๊ณผ null-์๋๋ ๋ง์กฑํด์ผ ํ์ง๋ง, ์ด ๋์ด ๋ฌธ์ ๋๋ ๊ฒฝ์ฐ๋ ๋ณ๋ก ์๋ค.
public class PhoneNumber {
private final short areaCode, prefix, lineNum;
public PhoneNumber(int areaCode, int prefix, int lineNum){
this.areaCode = rangeCheck(areaCode, 999, "์ง์ญ์ฝ๋");
this.prefix = rangeCheck(prefix, 999, "ํ๋ฆฌํฝ์ค");
this.lineNum = rangeCheck(lineNum, 9999, "๊ฐ์
์ ๋ฒํธ");
}
private static short rangeCheck(int val, int max, String arg){
if(val < 0 || val > max)
throw new IllegalArgumentException(arg + ": " + val);
return (short) val;
}
@Override
public boolean equals(Object o){
if(o == this)
return true;
if(!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber) o;
return pn.lineNum == lineNum && pn.prefix == prefix && pn.areaCode == areaCode;
}
}
๋ง์ง๋ง ์ฃผ์ ์ฌํญ
1. equals๋ฅผ ์ฌ์ ์ ํ ๋ hashCode๋ ๋ฐ๋์ ์ฌ์ ์ํ์(์์ดํ 11)
2. ๋๋ฌด ๋ณต์กํ๊ฒ ํด๊ฒฐํ๋ ค ๋ค์ง ๋ง์.
- ํ๋๋ค์ ๋์น์ฑ๋ง ๊ฒ์ฌํด๋ equals ๊ท์ฝ์ ์ด๋ ต์ง ์๊ฒ ์งํฌ ์ ์๋ค.
3. Object ์ธ์ ํ์ ์ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๋ equals ๋ฉ์๋๋ ์ ์ธํ์ง ๋ง์.
- ๋ง์ ํ๋ก๊ทธ๋๋จธ๊ฐ equals๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํด ๋๊ณ ๋ฌธ์ ์ ์์ธ์ ์ฐพ์ ํค๋งจ๋ค.
// ์
๋ ฅ ํ์
์ ๋ฐ๋์ Object์ฌ์ผ ํ๋ค., ์ปดํ์ผ ๋์ง ์๋๋ค.
@Override
public boolean equals(MyClass obj) {
}
ํต์ฌ ์ ๋ฆฌ
๊ผญ ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด equals๋ฅผ ์ฌ์ ์ํ์ง ๋ง์. ๋ง์ ๊ฒฝ์ฐ์ Object์ equals๊ฐ ์ฌ๋ฌ๋ถ์ด ์ํ๋ ๋น๊ต๋ฅผ ์ ํํ ์ํํด ์ค๋ค. ์ฌ์ ์ํด์ผ ํ ๋๋ ๊ทธ ํด๋์ค์ ํต์ฌ ํ๋ ๋ชจ๋๋ฅผ ๋น ์ง์์ด, ๋ค์ฏ ๊ฐ์ง ๊ท์ฝ์ ํ์คํ ์ง์ผ๊ฐ๋ฉฐ ๋น๊ตํด์ผ ํ๋ค.
.์์ดํ 11 - equals๋ฅผ ์ฌ์ ์ํ๋ ค๊ฑฐ๋ hashCode๋ ์ฌ์ ์ํ๋ผ
equals๋ฅผ ์ฌ์ ์ํ ํด๋์ค ๋ชจ๋์์ hashCode๋ ์ฌ์ ์ํด์ผ ํ๋ค.
- ๊ทธ๋ ์ง ์์ผ๋ฉด hashCode ์ผ๋ฐ ๊ท์ฝ์ ์ด๊ธฐ๊ฒ ๋์ด ํด๋น ํด๋์ค์ ์ธ์คํด์ค๋ฅผ HashMap์ด๋ HashSet ๊ฐ์ ์ปฌ๋ ์ ์ ์์๋ก ์ฌ์ฉํ ๋ ๋ฌธ์ ๋ฅผ ์ผ์ผํจ๋ค. ๋ค์์ Object ๋ช ์ธ์์ ๋ฐ์ทํ ๊ท์ฝ์ด๋ค.
- equals ๋น๊ต์ ์ฌ์ฉ๋๋ ์ ๋ณด๊ฐ ๋ณ๊ฒฝ๋์ง ์์๋ค๋ฉด, ์ ํ๋ฆฌ์ผ์ด์ ์คํ๋๋ ๋์ ๊ทธ ๊ฐ์ฒด์ hashCode ๋ฉ์๋๋ ๋ช ๋ฒ์ ํธ์ถํด๋ ์ผ๊ด๋ ๊ฐ์ ๋ฐํํด์ผ ํ๋ค. ๋จ, ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฌ์คํ๋๋ฉด ๋ฌ๋ผ์ ธ๋ ์๊ด์๋ค.
- equals(Object)๊ฐ ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ค๊ณ ํ๋จํ๋ค๋ฉด, ๋ ๊ฐ์ฒด์ hashCode๋ ๋๊ฐ์ ๊ฐ์ ๋ฐํํด์ผ ํ๋ค.
- equals(Object)๊ฐ ๋ ๊ฐ์ฒด๋ฅผ ๋ค๋ฅด๋ค๊ณ ํ๋จํ๋๋ผ๋, ๋ ๊ฐ์ฒด์ hashCode๊ฐ ์๋ก ๋ค๋ฅธ ๊ฐ์ ๋ฐํํ ํ์๋ ์๋ค. ๋จ, ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ํด์๋ ๋ค๋ฅธ ๊ฐ์ ๋ฐํํด์ผ ํด์ํ ์ด๋ธ์ ์ฑ๋ฅ์ด ์ข์์ง๋ค.
hashCode ์ฌ์ ์๋ฅผ ์๋ชปํ์ ๋ ํฌ๊ฒ ๋ฌธ์ ๊ฐ ๋๋ ์กฐํญ์ด ๋ ๋ฒ์งธ์ด๋ค. ๋ ผ๋ฆฌ์ ์ผ๋ก ๊ฐ์ ๊ฐ์ฒด๋ ๊ฐ์ hashCode๋ฅผ ๋ฐํํด์ผ ํ๋ค.
Map<PhoneNumber, String> m = new HashMap<>();
// 1
m.put(new PhoneNumber(707, 867, 5309), "์ ๋");
// 2
m.get(new PhoneNumber(707, 867, 5309))
์์ ์ฝ๋์์ 1์ ์คํํ ํ 2๋ฅผ ์คํํ๋ฉด "์ ๋"๊ฐ ๋์ค๊ธธ ๊ธฐ๋ํ์ง๋ง null ๊ฐ์ด ๋์ค๊ฒ ๋๋ค.
PhoneNumber ํด๋์ค์์ hashCode๋ฅผ ์ฌ์ ์ ํ์ง ์์๊ธฐ ๋๋ฌธ์ ๋ ผ๋ฆฌ์ ๋์น์ธ ๋ ๊ฐ์ฒด๊ฐ ์๋ก ๋ค๋ฅธ hashCode๋ฅผ ๋ฐํํ์ฌ ๋ ๋ฒ์งธ ๊ท์ฝ์ ์งํค์ง ๋ชปํ๋ค.
์๋์ ๊ฐ์ด PhoneNumber ํด๋์ค ์์ equals์ hashCode๋ฅผ ๊ตฌํํด ์ฃผ๋ฉด ๊ธฐ๋ํ ๊ฐ์ ๋ฐ์ ์ ์๋ค.
public class PhoneNumber {
private final int areaCode;
private final int prefix;
private final int lineNum;
public PhoneNumber(int areaCode, int prefix, int lineNum) {
this.areaCode = areaCode;
this.prefix = prefix;
this.lineNum = lineNum;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PhoneNumber that = (PhoneNumber) o;
return areaCode == that.areaCode && prefix == that.prefix && lineNum == that.lineNum;
}
@Override
public int hashCode() {
return Objects.hash(areaCode, prefix, lineNum);
}
}
ํด์ ์ถฉ๋์ด ๋์ฑ ์ ์ ๋ฐฉ๋ฒ์ ์จ์ผ ํ๋ค๋ฉด ๊ตฌ์๋ฐ์ com.google.common.hash.Hashing์ ์ฐธ๊ณ ํ์
ํด๋์ค๊ฐ ๋ถ๋ณ์ด๊ณ hashCode๋ฅผ ๊ณ์ฐํ๋ ๋น์ฉ์ด ํฌ๋ค๋ฉด, ๋งค๋ฒ ์๋ก ๊ณ์ฐํ๊ธฐ๋ณด๋ค๋ ์บ์ฑํ๋ ๋ฐฉ์์ ๊ณ ๋ คํด์ผ ํ๋ค.
์ด ํ์ ์ ๊ฐ์ฒด๊ฐ ์ฃผ๋ก ํด์์ ํค๋ก ์ฌ์ฉ๋ ๊ฒ ๊ฐ๋ค๋ฉด ์ธ์คํด์ค๊ฐ ๋ง๋ค์ด์ง ๋ ํด์์ฝ๋๋ฅผ ๊ณ์ฐํด ๋๋ค.
ํด์ ํค๋ก ์ฌ์ฉ๋์ง ์๋ ๊ฒฝ์ฐ๋ผ๋ฉด hashCode๊ฐ ์ฒ์ ๋ถ๋ฆด ๋ ๊ณ์ฐํ๋ ์ง์ฐ ์ด๊ธฐํ ์ ๋ต์ ์ฌ์ฉํ๋ฉด ์ด๋จ๊น? ์ด๋ฌํ ์ง์ฐ ์ด๊ธฐํ ์ ๋ต์ ์ฌ์ฉํ๋ ค๋ฉด ํด๋์ค์ ์ค๋ ๋๋ฅผ ์์ ํ๊ฒ ๋ง๋ค๋๋ก ์ ๊ฒฝ ์จ์ผ ํ๋ค(์์ดํ 83)
์์๋ ๋ค์๊ณผ ๊ฐ๋ค
private int hashCode; // ์๋์ผ๋ก 0์ผ๋ก ์ด๊ธฐํ
public int hashCode2() {
int result = hashCode;
if(result == 0) {
Integer.hashCode(areaCode);
result = 31 * result + Integer.hashCode(prefix);
result = 31 * result + Integer.hashCode(lineNum);
hashCode = result;
}
return result;
}
์ฑ๋ฅ์ ๋์ด๊ธฐ ์ํด hashCode ๊ณ์ฐ์์ ํต์ฌ ํ๋๋ฅผ ์๋ตํด์๋ ์ ๋๋ค.
- ์๋์ผ ๋นจ๋ผ์ง์ง๋ง, hash ํ์ง์ด ์ ํ๋์ด hashTable์ ์ฑ๋ฅ์ ์ฌ๊ฐํ๊ฒ ๋จ์ด๋จ๋ฆด ์ ์๋ค.
hashCode๊ฐ ๋ฐํํ๋ ๊ฐ์ ์์ฑ ๊ท์น์ API ์ฌ์ฉ์์๊ฒ ์์ธํ ๊ณตํํ์ง ๋ง์. ๊ทธ๋์ผ ํด๋ผ์ด์ธํธ๊ฐ ์ด ๊ฐ์ ์์งํ์ง ์๊ฒ ๋๊ณ , ์ถํ์ ๊ณ์ฐ ๋ฐฉ์์ ๋ฐ๊ฟ ์๋ ์๋ค.
ํต์ฌ ์ ๋ฆฌ
equals๋ฅผ ์ฌ์ ์ํ ๋๋ hashCode๋ ๋ฐ๋์ ์ฌ์ ์ํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ํ๋ก๊ทธ๋จ์ด ์ ๋๋ก ๋์ํ์ง ์์ ๊ฒ์ด๋ค. ์ฌ์ ์ํ hashCode๋ Object์ API ๋ฌธ์์ ๊ธฐ์ ๋ ์ผ๋ฐ ๊ท์ฝ์ ๋ฐ๋ผ์ผ ํ๋ค.
.์์ดํ 12 - toString์ ํญ์ ์ฌ์ ์ํ๋ผ
Object์ ๊ธฐ๋ณธ toString ๋ฉ์๋๋ ์ฐ๋ฆฌ๊ฐ ์์ฑํ ํด๋์ค์ ์ ํฉํ ๋ฌธ์์ด์ ๋ฐํํ๋ ๊ฒฝ์ฐ๊ฐ ๊ฑฐ์ ์๋ค. ์ด ๋ฉ์๋๋ PhoneNumber@adbbd ์ฒ๋ผ ๋จ์ํ 'ํด๋์ค_์ด๋ฆ@16์ง์๋กํ์ํHashCode'๋ฅผ ๋ฐํํ ๋ฟ์ด๋ค.
toString์ ์ผ๋ฐ ๊ท์ฝ์ ๋ฐ๋ฅด๋ฉด '๊ฐ๊ฒฐํ๋ฉด์ ์ฌ๋์ด ์ฝ๊ธฐ ์ฌ์ด ํํ์ ์ ์ตํ ์ ๋ณด'๋ฅผ ๋ฐํํด์ผ ํ๋ค. ๋ํ '๋ชจ๋ ํ์ ํด๋์ค์์ ์ด ๋ฉ์๋๋ฅผ ์ฌ์ ์ํ๋ผ' ๋ผ๊ณ ๊ท์ฝ ๋์ด์๋ค.
toString์ด ์์ equals์ hashCode ๋งํผ ์ค์ํ์ง๋ ์์ง๋ง. toString์ ์ ๊ตฌํํ ํด๋์ค๋ ์ฌ์ฉํ๊ธฐ์ ํจ์ฌ ์ข๊ณ , ๋๋ฒ๊น ๋ํ ์ฝ๋ค. toString ๋ฉ์๋๋ ๊ฐ์ฒด๋ฅผ println, printf, ๋ฌธ์์ด ์ฐ๊ฒฐ(+), assert ๊ตฌ๋ฌธ์ ๋๊ธธ ๋, ํน์ ๋๋ฒ๊ฑฐ๊ฐ ๊ฐ์ฒด๋ฅผ ์ถ๋ ฅํ ๋ ์๋์ผ๋ก ๋ถ๋ฆฐ๋ค. ์ง์ ํธ์ถํ์ง ์์๋ ์ด๋์ ๊ฐ ์ฐ์ด๊ฒ ๋๋ค.
์ค์ ์์ toString์ ๊ฐ์ฒด๊ฐ ๊ฐ์ง ์ฃผ์ํ ์ ๋ณด๋ฅผ ๋ชจ๋ ๋ฐํํ๋ ๊ฒ ์ข๋ค.
toString์ ํฌ๋งท์ ๋ช ์ํ๋ ๊ฒ ํ์๋ ์๋์ง๋ง ์๋๋ ๋ช ํํ ๋ฐํ์ผ ํ๋ค.
/**
* ํฐ ๋ฒํธ๋ฅผ ๋ฌธ์์ด๋ก ๋ฐํ
* PhoneNumber{areaCode=82, prefix=10, lineNum=1234}
*/
@Override
public String toString() {
return "PhoneNumber{" +
"areaCode=" + areaCode +
", prefix=" + prefix +
", lineNum=" + lineNum +
'}';
}
ํฌ๋งท ๋ช ์ ์ฌ๋ถ์ ์๊ด์์ด toString์ด ๋ฐํํ ๊ฐ์ ํฌํจ๋ ์ ๋ณด๋ฅผ ์ป์ด์ฌ ์ ์๋ APi๋ฅผ ์ ๊ณตํ์.
์๋ก PhoneNumber ํด๋์จ๋ ๊ฐ๊ฐ ์ง์ญ์ฝ๋, ํ๋ฆฌํฝ์ค, ๊ฐ์ ์ ๋ฒํธ์ฉ ์ ๊ทผ์๋ฅผ ์ ๊ณตํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ด ์ ๋ณด๊ฐ ํ์ํ ํ๋ก๊ทธ๋๋จธ๋ toString์ ๋ฐํ๊ฐ์ ํ์ฑ ํ ์๋ฐ์ ์๋ค.
์ ์ ์ ํธ๋ฆฌํฐ ํด๋์ค(์์ดํ 4)๋ toString์ ์ ๊ณตํ ์ด์ ๊ฐ ์๋ค.. ๋ํ, ๋๋ถ๋ถ์ ์ด๊ฑฐ ํ์ (์์ดํ 34)๋ ์๋ฐ๊ฐ ์ด๋ฏธ ์๋ฒฝํ toString์ ์ ๊ณตํ์ฌ ๋ฐ๋ก ์ฌ์ ์ ํ์ง ์์๋ ๋๋ค. ํ์ง๋ง ํ์ ํด๋์ค๋ค์ด ๊ณต์ ํด์ผ ํ ๋ฌธ์์ด ํํ์ด ์๋ ์ถ์ ํด๋์ค๋ผ๋ฉด toString์ ์ฌ์ ์ ํด์ค์ผ ํ๋ค. ์๋ก ๋๋ค์์ ์ปฌ๋ ์ ๊ตฌํ์ฒด๋ ์ถ์ ์ปฌ๋ ์ ํด๋์ค๋ค์ toString ๋ฉ์๋๋ฅผ ์์ํด ์ด๋ค.
Object์ toString๋ณด๋ค๋ Lombok์ด๋ AutoValue์ ์๋ ์์ฑ toString์ด๋ผ๋ ์ฌ์ฉํ์.
ํต์ฌ ์ ๋ฆฌ
๋ชจ๋ ๊ตฌ์ฒด ํด๋์ค์์ Object์ toString์ ์ฌ์ ์ํ์. ์์ ํด๋์ค์์ ์ด๋ฏธ ์๋ง๊ฒ ์ฌ์ ์ํ ๊ฒฝ์ฐ๋ ์์ธ๋ค.
toString์ ์ฌ์ ์ํ ํด๋์ค๋ ์ฌ์ฉํ๊ธฐ๋ ์ฆ๊ฒ๊ณ ๊ทธ ํด๋์ค๋ฅผ ์ฌ์ฉํ ์์คํ ์ ๋๋ฒ๊น ํ๊ธฐ ์ฝ๊ฒ ํด ์ค๋ค. toString์ ํด๋น ๊ฐ์ฒด์ ๊ดํ ๋ช ํํ๊ณ ์ ์ฉํ ์ ๋ณด๋ฅผ ์ฝ๊ธฐ ์ข์ ํํ๋ก ๋ฐํํด์ผ ํ๋ค.
.์์ดํ 13 - clone ์ฌ์ ์๋ ์ฃผ์ํด์ ์งํํ๋ผ
Cloneable์ ๋ณต์ ํด๋ ๋๋ ํด๋์ค์์ ๋ช ์ํ๋ ์ฉ๋์ ๋ฏน์ค์ธ ์ธํฐํ์ด์ค(mixin interface, ์์ดํ 20)์ง๋ง Cloneable์ ๊ตฌํํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ธ๋ถ ๊ฐ์ฒด์์ clone ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์๋ค. clone ๋ฉ์๋๊ฐ ์ ์ธ๋ ๊ณณ์ด Cloneable์ด ์๋ Object์ด๊ณ , ๊ทธ๋ง์ ๋ protected๋ผ์ ์ด๋ค.
package java.lang;
public interface Cloneable {
}
๋ฉ์๋ ํ๋ ์๋ Cloneable ์ธํฐํ์ด์ค๊ฐ ํ๋ ์ผ์ ๋ญ๊น?
- Object์ protected ๋ฉ์๋์ธ clone์ ๋์ ๋ฐฉ์์ ๊ฒฐ์ ํ๋ค.
//Object Class clone()
@HotSpotIntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;
- Clonable์ ๊ตฌํํ ํด๋์ค์ ์ธ์คํด์ค์์ clone์ ํธ์ถํ๋ฉด ๊ทธ ๊ฐ์ฒด์ ํ๋๋ค์ ํ๋ํ๋ ๋ณต์ฌํ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ฉฐ, ๊ทธ๋ ์ง ์์ ํด๋์ค์ ์ธ์คํด์ค์์ ํธ์ถํ๋ฉด 'CloneNotSupportedException'์ ๋์ง๋ค.
์ค๋ฌด์์ Cloneable์ ๊ตฌํํ ํด๋์ค๋ clone ๋ฉ์๋๋ฅผ public์ผ๋ก ์ ๊ณตํ๋ฉฐ, ์ฌ์ฉ์๋ ๋น์ฐํ ๋ณต์ ๊ฐ ์ ๋๋ก ์ด๋ค์ง๋ฆฌ๋ผ ๊ธฐ๋ํ๋ค.
clone ๋ฉ์๋์ ์ผ๋ฐ ๊ท์ฝ์ ํ์ ํ๋ค. ๋ค์์ Object ๋ช ์ธ์ด๋ค.
์ด ๊ฐ์ฒด์ ๋ณต์ฌ๋ณธ์ ์์ฑํด ๋ฐํํ๋ค. '๋ณต์ฌ'์ ์ ํํ ๋ป์ ๊ทธ ๊ฐ์ฒด๋ฅผ ๊ตฌํํ ํด๋์ค์ ๋ฐ๋ผ ๋ค๋ฅผ ์ ์๋ค.
1.x.clone() != x
2.x.clone().getClass() == x.getClass()
3.x.clone().equals(x)
๊ด๋ก์ ์ ๋ฉ์๋๋ค์ ์ฐธ์ด์ง๋ง, ํ์๋ ์๋๋ฏ๋ก ๊ฐ์ ์ฑ์ด ์๋ค.
์ฆ, clone ๋ฉ์๋๊ฐ super.clone์ด ์๋, ์์ฑ์๋ฅผ ํธ์ถํด ์ป์ ์ธ์คํด์ค๋ฅผ ๋ฐํํด๋ ์ปดํ์ผ๋ฌ๋ ๋ถํํ์ง ์๋๋ค. ํ์ง๋ง ์ด ํด๋์ค์ ํ์ ํด๋์ค์์ super.clone์ ํธ์ถํ๋ค๋ฉด ์๋ชป๋ ํด๋์ค์ ๊ฐ์ฒด๊ฐ ๋ง๋ค์ด์ ธ ๊ฒฐ๊ตญ ํ์ ํด๋์ค์ clone ๋ฉ์๋๊ฐ ์ ๋๋ก ๋์ํ์ง ์๊ฒ ๋๋ค.
public static void main(String[] args) throws CloneNotSupportedException {
B b1 = new B();
B b2 = new A();
Object cloneB1 = b1.clone();
Object cloneB2 = b2.clone();
System.out.println(cloneB1.getClass()); // B
System.out.println(cloneB2.getClass()); // A
System.out.println(cloneB1.getClass() == cloneB2.getClass()); // false
}
static class B implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class A extends B implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
clone์ ์ฌ์ ์ํ ํด๋์ค๊ฐ final์ด๋ผ๋ฉด ๊ฑฑ์ ํด์ผ ํ ํ์ ํด๋์ค๊ฐ ์์ผ๋ ์ด ๊ด๋ก๋ ๋ฌด์ํด๋ ์์ ํ๋ค. ํ์ง๋ง final ํด๋์ค์ clone ๋ฉ์๋๊ฐ super.clone์ ํธ์ถํ์ง ์๋๋ค๋ฉด Cloneable์ ๊ตฌํํ ์ด์ ๋ ์๋ค. Object์ clone ๊ตฌํ์ ๋์ ๋ฐฉ์์ ๊ธฐ๋ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ชจ๋ ํ๋๊ฐ ๊ธฐ๋ณธ ํ์ ์ด๊ฑฐ๋ ๋ถ๋ณ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ค๋ฉด ์ด ๊ฐ์ฒด๋ ์๋ฒฝํ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์ํ๋ผ ๋ ์๋ณผ ๊ณณ์ด ์๋ค.
์ธ๋ฐ์๋ ๋ณต์ฌ๋ฅผ ์ง์ํ๋ค๋ ๊ด์ ์์ ๋ณด๋ฉด ๋ถ๋ณ ํด๋์จ๋ ๊ตณ์ด clone ๋ฉ์๋๋ฅผ ์ ๊ณตํ์ง ์๋ ๊ฒ ์ข๋ค.
public class PhoneNumber implements Cloneable {
private final short areaCode, prefix, lineNum;
public PhoneNumber(short areaCode, short prefix, short lineNum) {
this.areaCode = areaCode;
this.prefix = prefix;
this.lineNum = lineNum;
}
@Override
public PhoneNumber clone() {
try {
return (PhoneNumber) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // ๋ชจ๋ ํ๋๊ฐ ๊ธฐ๋ณธ ํ์
์ด๊ธฐ ๋๋ฌธ์ ์ผ์ด๋ ์ ์๋ ์ผ์ด๋ค. or ๋ถ๋ณ๊ฐ์ฒด์๊ฒฝ์ฐ
}
}
}
์ฌ์ ์ํ ๋ฉ์๋์ ๋ฐํ ํ์ ์ ์์ ํด๋์ค์ ๋ฉ์๋๊ฐ ๋ฐํํ๋ ํ์ ํ์ ์ผ ์ ์๋ค. ์ด ๋ฐฉ์์ผ๋ก ํด๋ผ์ด์ธํธ๊ฐ ํ๋ณํ ํ์ง ์์๋ ๋๊ฒ๋ ํด์ฃผ์. ์ด๋ฅผ ์ํด ์ ์ฝ๋์์๋ super.clone์์ ์ป์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๊ธฐ ์ ์ PhoneNumber๋ก ํ๋ณํํ์๋ค.
super.clone์ try-catch๋ก ๊ฐ์ผ ์ด์ ๋ Object์ clone ๋ฉ์๋๊ฐ ๊ฒ์ฌ ์์ธ์ธ CloneNotSupportedExceptoin์ ๋์ง๋๋ก ์ ์ธ๋์ด์๊ธฐ ๋๋ฌธ์ด๋ค. ์ฐ๋ฆฌ๋ ์ฑ๊ณตํ ๊ฒ์์ ์๊ณ ์๋ค. ์ฌ์ค์ ๋น๊ฒ์ฌ ์์ธ์๋ค๋ ์ ํธ๋ค(์์ดํ 71)
๋ค์์ ๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ์๊ฐ์ด๋ค.
public class Stack implements Cloneable{
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
this.elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e){
ensureCapacity();
elements[size++] = e;
}
public Object pop(){
if(size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // ๋ค ์ด ์ฐธ์กฐ ํด์
return result;
}
/**
* ์์๋ฅผ ์ํ ๊ณต๊ฐ์ ์ ์ด๋ ํ๋ ์ด์ ํ๋ณดํ๋ค.
* ๋ฐฐ์ด ํฌ๊ธฐ๋ฅผ ๋๋ ค์ผ ํ ๋๋ง๋ค ๋๋ต ๋ ๋ฐฐ์ฉ ๋๋ฆฐ๋ค.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = java.util.Arrays.copyOf(elements, 2 * size + 1);
}
@Override
public Stack clone() {
try {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // ์ผ์ด๋ ์ ์๋ ์ผ์ด๋ค.
}
}
}
๋ง์ผ ๋จ์ํ super.clone๊ฐ์ ์๋์ ๊ฐ์ด ๋ฐํํ๋ค๋ฉด?
@Override
public Stack clone() {
try {
Stack clone = (Stack) super.clone();
// TODO: copy mutable state here, so the clone can't change the internals of the original
return clone;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
- size ํ๋๋ ์ฌ๋ฐ๋ฅธ ๊ฐ์ ๊ฐ์ง๋ง, elements ํ๋๋ ์๋ณธ Stack ์ธ์คํด์ค์ ๋๊ฐ์ ๋ฐฐ์ด์ ์ฐธ์กฐํ ๊ฒ์ด๋ค. ์๋ณธ์ด๋ ๋ณต์ ๋ณธ ์ค ํ๋๋ฅผ ์์ ํ๋ฉด ๋ค๋ฅธ ํ๋๋ ์์ ๋์ด ๋ถ๋ณ์์ ํด์น๊ฒ ๋๋ค. ๋ฐ๋ผ์ ํ๋ก๊ทธ๋จ์ด ์ํ๋ ๋๋ก ๋์ํ์ง ์๊ฒ ๋๋ค.
Stack ํด๋์ค์ ํ๋๋ฟ์ธ ์์ฑ์๋ฅผ ํธ์ถํ๋ฉด ์์ ์ํฉ์ ์ ๋ ์ผ์ด๋์ง ์๋๋ค. clone ๋ฉ์๋๋ ์ฌ์ค์ ์์ฑ์์ ๊ฐ์ ํจ๊ณผ๋ฅผ ๋ธ๋ค. ์ฆ , clone์ ์๋ณธ ๊ฐ์ฒด์ ์๋ฌด๋ฐ ํด๋ฅผ ๋ผ์น์ง ์๋ ๋์์ ๋ณต์ ๋ ๊ฐ์ฒด์ ๋ถ๋ณ์์ ๋ณด์ฅํด์ผ ํ๋ค.
๊ทธ๋ฌ๊ธฐ ์ํด Stack์ clone ๋ฉ์๋๋ ์ ๋๋ก ๋์ํ๋ ค๋ฉด ์คํ ๋ด๋ถ ์ ๋ณด๋ฅผ ๋ณต์ฌํด์ผ ํ๋๋ฐ, ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ผ๋ก elements ๋ฐฐ์ด์ clone์ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํด ์ฃผ๋ ๊ฒ์ด๋ค.
@Override
public Stack clone() {
try {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // ์ผ์ด๋ ์ ์๋ ์ผ์ด๋ค.
}
}
์์ elements.clone() ์์ Object[]๋ก ํ๋ณํํ ํ์๋ ์๋ค. ๋ฐฐ์ด์ clone์ ๋ฐํ์ ํ์ ๊ณผ ์ปดํ์ผํ์ ํ์ ๋ชจ๋๊ฐ ์๋ณธ ๋ฐฐ์ด๊ณผ ๋๊ฐ์ ๋ฐฐ์ด์ ๋ฐํํ๋ค. ๋ฐ๋ผ์ ๋ฐฐ์ด์ ๋ณต์ ํ ๋๋ ๋ฐฐ์ด์ clone ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ผ๊ณ ๊ถ์ฅํ๋ค. ์ฌ์ค, ๋ฐฐ์ด์ clone ๊ธฐ๋ฅ์ ์ ๋๋ก ์ฌ์ฉํ๋ ์ ์ผํ ์๋ผ ํ ์ ์๋ค.
ํํธ, elements ํ๋๊ฐ final์ด์๋ค๋ฉด ์์์ ๋ฐฉ์์ ์๋ํ์ง ์๋๋ค. final ํ๋์๋ ์๋ก์ด ๊ฐ์ ํ ๋นํ ์ ์ ์ ๋๋ฌธ์ด๋ค. ์ด๋ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ก, ์ง๋ ฌํ์ ๋ง์ฐฌ๊ฐ์ง๋ก Cloneable ์ํคํ ์ฒ๋ '๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ํ๋๋ final๋ก ์ ์ธํ๋ผ'๋ ์ผ๋ฐ ์ฉ๋ฒ๊ณผ ์ถฉ๋ํ๋ค.
clone์ ์ฌ๊ท์ ํธ์ถํ๋ ๊ฒ๋ง์ผ๋ก ์ถฉ๋ถํ์ง ์์ ๋๋ ์๋ค. ํด์ ํ ์ด๋ธ์ ์๋ก ๋ณด๋ฉด ๋ด๋ถ๋ ๋ฒํท๋ค์ ๋ฐฐ์ด์ด๊ณ ๋ฒํท์key-value๋ก ์ด๋ฃจ์ด์ง ์ํธ๋ฆฌ์ด๋ค. clone์ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, Cloneable, Serializable {
private transient Entry<?, ?>[] table;
public synchronized Object clone() {
Hashtable<?, ?> t = this.cloneHashtable();
t.table = new Entry[this.table.length];
for(int i = this.table.length; i-- > 0; t.table[i] = this.table[i] != null ? (Entry)this.table[i].clone() : null) {
}
t.keySet = null;
t.entrySet = null;
t.values = null;
t.modCount = 0;
return t;
}
private static class Entry<K, V> implements Map.Entry<K, V> {
final int hash;
final K key;
V value;
Entry<K, V> next;
protected Object clone() {
return new Entry(this.hash, this.key, this.value, this.next == null ? null : (Entry)this.next.clone());
}
}
}
์์ stack ์ฒ๋ผ elements(HashTable์ table)์ ๋ณต์ฌํ์ง ์๊ณ ์ํํ๋ฉฐ entry์ ๋ณต์ฌ๋ฅผ ์งํํ๋ค.
์์ฑ์์์๋ ์ฌ์ ์๋ ์ ์๋ ๋ฉ์๋๋ฅผ ํธ์ถํ์ง ์์์ผ ํ๋๋ฐ(์์ดํ 19) clone ๋ฉ์๋๋ ๋ง์ฐฌ๊ฐ์ง๋ค. ๋ง์ฝ clone์ด ํ์ ํด๋์ค์์ ์ฌ์ ์ํ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด, ํ์ ํด๋์ค๋ ๋ณต์ ๊ณผ์ ์์ ์์ ์ ์ํ๋ฅผ ๊ต์ ํ ๊ธฐํ๋ฅผ ์๊ฒ ๋์ด ์๋ณธ๊ฐ ๋ณต์ ๋ณธ์ ์ํ๊ฐ ๋ฌ๋ผ์ง ๊ฐ๋ฅ์ฑ์ด ํฌ๋ค.
Object์ clone ๋ฉ์๋๋ CloneNotSupportedException์ ๋์ง๋ค๊ณ ์ ์ธํ์ง๋ง ์ฌ์ ์ํ ๋ฉ์๋๋ ๊ทธ๋ ์ง ์๋ค. public์ธ clone ๋ฉ์๋์์๋ throws ์ ์ ์์ ์ผ ํ๋ค. ๊ฒ์ฌ ์์ธ๋ฅผ ๋์ง์ง ์์์ผ ๊ทธ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ธฐ ํธํ๊ธฐ ๋๋ฌธ์ด๋ค.(์์ดํ 71)
์์ํด์ ์ฐ๊ธฐ ์ํ ํด๋์ค ์ค๊ณ ๋ฐฉ์ ๋ ๊ฐ์ง(์์ดํ 19) ์ค ์ด๋ ์ชฝ์์๋ , ์์์ฉ ํด๋์ค๋ Cloneable์ ๊ตฌํํด์๋ ์ ๋๋ค. Object์ ๋ฐฉ์์ ๋ชจ๋ฐฉํ ์๋ ์๋ค. ์ ๋๋ก ์๋ํ๋ clone ๋ฉ์๋๋ฅผ ๊ตฌํํด protected๋ก ๋๊ณ CloneNotSupportedException๋ ๋์ง ์ ์๋ค๊ณ ์ ์ธํ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฌ๋ฏ๋ก ํ์ ํด๋์ค์์ clone์ ์ฌ์ ์ํ์ง ๋ชปํ๊ฒ ํ๋ค.
@Override
protected final Object clone() throws CloneNotSupportedException {
return new CloneNotSupportedException();
}
Cloneable์ ๊ตฌํํ ์ค๋ ๋ ์์ ํด๋์ค๋ฅผ ์์ฑํ ๋๋ clone ๋ฉ์๋ ์ญ์ ์ ์ ํ ๋๊ธฐํํด์ค์ผ ํ๋ค.(์์ดํ 78)
Object์ clone๋ฉ์๋๋ ๋๊ธฐํ๋ฅผ ์ ๊ฒฝ ์ฐ์ง ์๋๋ค. ๊ทธ๋ฌ๋ super.clone ํธ์ถ ์ธ์ ๋ค๋ฅธ ํ ์ผ์ด ์๋๋ผ๋ clone์ ์ฌ์ ์ํ๊ณ ๋๊ธฐํํด์ค์ผ ํ๋ค.
Cloneable์ ์ด๋ฏธ ๊ตฌํํ ํด๋์ค๋ฅผ ํ์ฅํ๋ค๋ฉด ์ด์ฉ ์ ์์ด clone์ ์ ์๋ํ๋๋ก ๊ตฌํํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ ์ํฉ์์๋ ๋ณต์ฌ ์์ฑ์์ ๋ณต์ฌ ํฉํฐ๋ฆฌ๋ก ๋ ๋์ ๊ฐ์ฒด ๋ณต์ฌ ๋ฐฉ์์ ํํ๋ค.
static class C {
// ๋ณต์ฌ ์์ฑ์
public C(C c) {
// ...
}
// ๋ณต์ฌ ํฉํ ๋ฆฌ
public static C newInstance(C c) {
// ...
return new C(c);
}
}
๋ณต์ฌ ์์ฑ์, ๋ณต์ฌ ํฉํฐ๋ฆฌ์ ๋ ์ ํํ ์ด๋ฆ์ ๋ณํ ์์ฑ์(conversion constructor)์ ๋ณํ ํฉํ ๋ฆฌ(conversion factory)์ด๋ค. ์ด๋ค์ ์ด์ฉํ๋ฉด ํด๋ผ์ด์ธํธ๋ ์๋ณธ์ ๊ตฌํ ํ์ ์ ์ฝ๋งค์ด์ง ์๊ณ ๋ณต์ ๋ณธ์ ํ์ ์ ์ง์ ์ ํํ ์ ์๋ค. ์๋ก HashSet์ ๊ฐ์ฒด s๋ฅผ TreeSet ํ์ ์ผ๋ก ๋ณต์ ํ ์ ์๋ค.
ํต์ฌ ์ ๋ฆฌ
Cloneable์ด ๋ชฐ๊ณ ์จ ๋ฌธ์ ๋ฅผ ๋์ง์ด ๋ดค์ ๋, ์๋ก์ด ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค ๋๋ ์ ๋ Cloneable์ ํ์ฅํด์๋ ์ ๋๋ฉฐ, ์๋ก์ด ํด๋์ค๋ ์ด๋ฅผ ๊ตฌํํด์๋ ์ ๋๋ค. final ํด๋์ค๋ผ๋ฉด Cloneable์ ๊ตฌํํด๋ ์ํ์ด ํฌ์ง ์์ง๋ง, ์ฑ๋ฅ ์ต์ ํ ๊ด์ ์์ ๊ฒํ ํ ํ ๋ณ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ์์ ๋๋ง ๋๋ฌผ๊ฒ ํ์ฉํด์ผ ํ๋ค(์์ดํ 67). ๊ธฐ๋ณธ ์์น์ '๋ณต์ ๊ธฐ๋ฅ์ ์์ฑ์์ ํฉํฐ๋ฆฌ๋ฅผ ์ด์ฉํ๋ ๊ฒ ์ต๊ณ '๋ผ๋ ๊ฒ์ด๋ค. ๋จ, ๋ฐฐ์ด๋ง์ clone ๋ฉ์๋ ๋ฐฉ์์ด ๊ฐ์ฅ ๊น๋ํ, ์ด ๊ท์น์ ํฉ๋นํ ์์ธ๋ค.
.์์ดํ 14 - Comparable์ ๊ตฌํํ ์ง ๊ณ ๋ คํ๋ผ.
public interface Comparable<T> {
int compareTo(T var1);
}
Comparable์ compareTo๋ฉ์๋๋ ๋ ๋จ์ ๋์น์ฑ ๋น๊ต์ ๋ํด ์์๊น์ง ๋น๊ตํ ์ ์์ผ๋ฉฐ ์ ๋ค๋ฆญ ํ๋ค.
Comparable์ ๊ตฌํํ๋ค๋ ๊ฒ์ ๊ทธ ํด๋์ค์ ์ธ์คํด์ค๋ค์๋ ์์ฐ์ ์ธ ์์๊ฐ ์์์ ๋ปํ๋ค.
์๋ฐ ํ๋ซํผ ๋ผ์ด๋ฒ๋ฆฌ๋ค์ ๋ชจ๋ ๊ฐ ํด๋์ค์ ์ด๊ฑฐ ํ์ (์์ดํ 34)์ด Comparable์ ๊ตฌํํ๋ค. ์ํ๋ฒณ, ์ซ์, ์ฐ๋ ๊ฐ์ด ์์๊ฐ ๋ช ํํ ๊ฐ ํด๋์ค๋ฅผ ์์ฑํ๋ค๋ฉด ๋ฐ๋์ Comparable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ์.
compareTo ๋ฉ์๋์ ์ผ๋ฐ ๊ท์ฝ์ ๋ค์๊ณผ ๊ฐ๊ณ equals์ ๊ท์ฝ๊ณผ ๋น์ทํ๋ค.
์ด ๊ฐ์ฒด์ ์ฃผ์ด์ง ๊ฐ์ฒด์ ์์๋ฅผ ๋น๊ตํ๋ค. ์ด ๊ฐ์ฒด๊ฐ ์ฃผ์ด์ง ๊ฐ์ฒด๋ณด๋ค ์์ ๊ฒฝ์ฐ ์์ ์ ์, ๊ฐ์ผ๋ฉด 0, ํฌ๋ฉด ์์ ์ ์๋ฅผ ๋ฐํํ๋ค. ์ด ๊ฐ์ฒด์ ๋น๊ตํ ์ ์๋ ํ์ ์ ๊ฐ์ฒด๊ฐ ์ฃผ์ด์ง๋ฉด ClassCastException์ ๋์ง๋ค.
๋ค์ ์ค๋ช ์์ sgn(ํํ์) ํ๊ธฐ๋ ์ํ์์ ๋งํ๋ ๋ถํธ ํจ์(signum function)์ ๋ปํ๋ฉฐ, ํํ์์ ๊ฐ์ด ์์, 0, ์์ ์ผ ๋ -1,0,1์ ๋ฐํํ๋๋ก ์ ์ํ๋ค.
- Comparable์ ๊ตฌํํ ํด๋์ค๋ ๋ชจ๋ x,y์ ๋ํด sgn(x.compareTo(y)) == -sgn(y.compareTo(x))์ฌ์ผ ํ๋ค. (์์ธ ์ฒ๋ฆฌ ์ญ์ ๋์ผ)
- Comparable์ ๊ตฌํํ ํด๋์ค๋ ์ถ์ด์ฑ์ ๋ณด์ฅํด์ผ ํ๋ค. ์ฆ, (x.compareTo(y) > 0 && y.compareTo(z) >0) ์ด๋ฉด x.compareTo(z) > 0์ด๋ค.
- Comparable์ ๊ตฌํํ ํด๋์ค๋ ๋ชจ๋ z์ ๋ํด x.compareTo(y) == 0 ์ด๋ฉด sgn(x.compareTo(z) == sgn(y.compareTo(z)) ๋ค.
- ๊ถ๊ณ ๊ฐ ํ์๋ ์๋์ง๋ง ๊ผญ ์งํฌ ์ฌํญ์ด๋ค. (x.compareTo(y) == 0) == (x.equals(y)) ์ฌ์ผ ํ๋ค. Comparable์ ๊ตฌํํ๊ณ ์ด ๊ถ๊ณ ๋ฅผ ์งํค์ง ์๋ ๋ชจ๋ ํด๋์ค๋ ๊ทธ ์ฌ์ค์ ๋ช ์ํด์ผ ํ๋ค. ๋ค์๊ณผ ๊ฐ์ด ๋ช ์ํ๋ฉด ์ ๋นํ ๊ฒ์ด๋ค.
*์ฃผ์: ์ดํด๋์ค์ ์์๋ equals์ ๋ฉ์๋์ ์ผ๊ด๋์ง ์๋ค
๋ชจ๋ ๊ฐ์ฒด์ ๋ํด ์ ์ญ ๋์น๊ด๊ณ๋ฅผ ๋ถ์ฌํ๋ equals ๋ฉ์๋์ ๋ฌ๋ฆฌ, compareTo๋ ํ์ ์ด ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ ๊ฒฝ ์ฐ์ง ์์๋ ๋๋ค. ํ์ ์ด ๋ค๋ฅธ ๊ฐ์ฒด๊ฐ ์ฃผ์ด์ง๋ฉด ๊ฐ๋จํ ClassCastException์ ๋์ ธ๋ ๋๋ฉฐ, ๋๋ถ๋ถ ๊ทธ๋ ๊ฒ ํ๋ค. ๋ฌผ๋ก ๊ณตํต ์ธํฐํ์ด์ค๋ฅผ ๋งค๊ฐ๋ก ์ด๋ค์ก์ ๊ฒฝ์ฐ๋ ๋ค๋ฅธ ํ์ ์ฌ์ด์ ๋น๊ต๋ ํ์ฉ๋๋ค.
hashCode ๊ท์ฝ์ ์งํค์ง ๋ชปํ๋ฉด ํด์๋ฅผ ์ฌ์ฉํ๋ ํด๋์ค์ ์ด์ธ๋ฆฌ์ง ๋ชปํ๋ฏ, compareTo ๊ท์ฝ์ ์งํค์ง ๋ชปํ๋ฉด ๋น๊ต๋ฅผ ํ์ฉํ๋ ํด๋์ค์ ์ด์ธ๋ฆฌ์ง ๋ชปํ๋ค. ์๋ก TreeSet๊ณผ TreeMap, ๊ฒ์๊ณผ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ํ์ฉํ๋ ์ ํธ๋ฆฌํฐ ํด๋์ค์ธ Collections์ Arrays๊ฐ ์๋ค.
compareTo์ ์์๊ฐ equals์ ๊ฒฐ๊ณผ๊ฐ ์ผ๊ด๋์ง ์์ ๊ฒฝ์ฐ ์๋ฐ์๊ฐ ๋ ์ ์๋ ๋ฐ ์๋ก ์ปฌ๋ ์ ์ธํฐํ์ด์ค์ ์ ์๋ ๋์์์ ์ด๋ค. ์ปฌ๋ ์ ์ธํฐํ์ด์ค๋ค์ equals ๋ฉ์๋์ ๊ท์ฝ์ ๋ฐ๋ฅธ๋ค๊ณ ๋์ด ์์ง๋ง, ์ ๋ ฌ๋ ์ปฌ๋ ์ ๋ค์ ๋์น์ฑ์ ๋น๊ตํ ๋ equals ๋์ compareTo๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ด๋ค. ์์ฃผ ํฐ ๋ฌธ์ ๋ ์๋์ง๋ง, ์ฃผ์ํด์ผ ํ๋ค.
compareTo์ equals๊ฐ ์ผ๊ด๋์ง ์๋ BigDecimal ํด๋์ค๋ฅผ ์๋ก ์๊ฐํด ๋ณด์. BigDecimal("1.0")๊ณผ BigDecimal("1.00")์ equals๋ฉ์๋๋ก ๋น๊ตํ๋ฉด ๋ค๋ฅด์ง๋ง compareTo ๋ฉ์๋๋ก ๋น๊ตํ๋ฉด ๋๊ฐ๋ค. ๋ฐ๋ผ์ ๊ฐ HashSet๊ณผ TreeSet์ ์ฝ์ ํ์ ๋ ์์์ ๊ฐ์๊ฐ ๋ค๋ฅด๋ค.
HashSet<BigDecimal> hashSet = new HashSet<>();
TreeSet<BigDecimal> treeSet = new TreeSet<>();
BigDecimal bigDecimal1 = new BigDecimal("1.0");
BigDecimal bigDecimal2 = new BigDecimal("1.00");
boolean compareTo = bigDecimal1.compareTo(bigDecimal2) == 0;
boolean equals = bigDecimal1.equals(bigDecimal2);
hashSet.add(bigDecimal1);
hashSet.add(bigDecimal2);
treeSet.add(bigDecimal1);
treeSet.add(bigDecimal2);
System.out.println(compareTo); // true
System.out.println(equals); // false
System.out.println(hashSet.size()); // 2
System.out.println(treeSet.size()); // 1
compreTo ๋ฉ์๋๋ ๊ฐ ํ๋๊ฐ ๋์น์ธ์ง๋ฅผ ๋น๊ตํ๋ ๊ฒ ์๋๋ผ ๊ทธ ์์๋ฅผ ๋น๊ตํ๋ค. ๊ฐ์ฒด ์ฐธ์กฐ ํ๋๋ฅผ ๋น๊ตํ๋ ค๋ฉด compreTo ๋ฉ์๋๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํ๋ค. Comprable์ ๊ตฌํํ์ง ์์ ํ๋๋ ํ์ค์ด ์๋ ์์๋ก ๋น๊ตํด์ผ ํ๋ค๋ฉด ๋น๊ต์(Comprable)๋ฅผ ๋์ ์ฌ์ฉํ๋ค. ๋น๊ต์๋ ์ง์ ๋ง๋ค๊ฑฐ๋ ์๋ฐ๊ฐ ์ ๊ณตํ๋ ๊ฒ ์ค ๊ณจ๋ผ ์ฐ๋ฉด ๋๋ค.
์๋๋ CaseInsensitivieString์ด Comprable<CaseInsensitivieString>์ ๊ตฌํํ ๊ฒ์ผ๋ก CaseInsensitivieString ์ฐธ์กฐ์๋ง ๋น๊ตํ ์ ์๋ค๋ ๋ป์ด๋ค. Comparable์ ๊ตฌํํ ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฐ๋ฅด๋ ํจํด์ด๋ค.
public final class CaseInsensitiveString implements Comparable<CaseInsensitiveString>{
private final String s;
public CaseInsensitiveString(String s){
if(s == null)
throw new NullPointerException();
this.s = s;
}
@Override
public int compareTo(CaseInsensitiveString cis) {
return String.CASE_INSENSITIVE_ORDER.compare(s, cis.s);
}
}
์ฑ ์ 2ํ์์๋ ์ ์ ๊ธฐ๋ณธ ํ์ ํ๋๋ฅผ ๋น๊ตํ ๋ ๊ด๊ณ์ฐ์ฐ์์ธ <์ >๋ฅผ, ์ค์ ๊ธฐ๋ณธ ํ์ ํ๋๋ฅผ ๋น๊ตํ ๋๋ ์ ์ ๋ฉ์๋์ธ Double.compre์ Float.compare ์ฌ์ฉ์ ๊ถํ์ง๋ง ์๋ฐ 7๋ถํฐ ๋ฐ์ฑ ๋ ๊ธฐ๋ณธ ํ์ ํด๋์ค๋ค์ ์๋ก ์ถ๊ฐ๋ ์ ์ ๋ฉ์๋ compre๋ฅผ ์ด์ฉํ๋ฉด ๋๊ฒ ๋์๋ค. compreTo ๋ฉ์๋์์ ๊ด๊ณ ์ฐ์ฐ์ <์ >๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ฐฉ์์ ๊ฑฐ์ถ์ฅ์ค๋ฝ๊ณ ์ค๋ฅ๋ฅผ ์ ๋ฐํ๋, ์ด์ ๋ ์ถ์ฒํ์ง ์๋๋ค.
์๋ฐ 8์์๋ Comprator ์ธํฐํ์ด์ค๊ฐ ์ผ๋ จ์ ๋น๊ต์ ์์ฑ ๋ฉ์๋(comparator construction method)์ ํ์ ๊พธ๋ ค ๋ฉ์๋ ์ฐ์ ๋ฐฉ์์ผ๋ก ๋น๊ต์๋ฅผ ์์ฑํ ์ ์๊ฒ ๋์๋ค.
@Override
public int compareTo(PhoneNumber pn) {
int result = Short.compare(areaCode, pn.areaCode);
if(result == 0){
result = Short.compare(prefix, pn.prefix);
if(result == 0)
result = Short.compare(lineNum, pn.lineNum);
}
return 0;
}
์์ ์ ์ฉํ ๋ชจ์ต์ด๋ค. ๊ฐ๊ฒฐํ๊ฒ ๋ณํ์ง๋ง ๋ค์ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ ์ ์๋ค.
private static final Comparator<PhoneNumber> COMPARATOR =
comparingInt((PhoneNumber pn) -> pn.areaCode)
.thenComparingInt(pn -> pn.prefix)
.thenComparingInt(pn -> pn.lineNum);
@Override
public int compareTo(PhoneNumber pn) {
return COMPARATOR.compare(this, pn);
}
์ด๋ฐ๊ธ '๊ฐ์ ์ฐจ'๋ฅผ ๊ธฐ์ค์ผ๋ก ์ฒซ ๋ฒ์งธ ๊ฐ์ด ๋ ๋ฒ์งธ ๊ฐ๋ณด๋ค ์์ผ๋ฉด ์์๋ฅผ, ๋ ๊ฐ์ด ๊ฐ์ผ๋ฉด 0์, ์ฒซ ๋ฒ์งธ ๊ฐ์ด ํฌ๋ฉด ์์๋ฅผ ๋ฐํํ๋ compreTo๋ compre๋ฉ์๋์ ๋ง์ฃผํ ๊ฒ์ด๋ค. ๋ค์์ด ์์ด๋ค.
static Comparator<Object> hashCodeOrder = new Comparator<>() {
@Override
public int compare(Object o1, Object o2) {
return o1.hashCode() - o2.hashCode();
}
};
์ด ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ์ ๋๋ค. ์ ์ ์ค๋ฒํ๋ก๋ฅผ ์ผ์ผํค๊ฑฐ๋ IEEE 754 ๋ถ๋์์์ ๊ณ์ฐ ๋ฐฉ์์ ๋ฐ๋ฅธ ์ค๋ฅ๋ฅผ ๋ผ ์ ์๋ค. ๋ฐ๋ผ์ ๋ค์ ๋ ๋ฐฉ์ ์ค ํ๋๋ฅผ ์ฌ์ฉํ์.
static Comparator<Object> hashCodeOrder1 = new Comparator<>() {
@Override
public int compare(Object o1, Object o2) {
return Integer.compare(o1.hashCode(), o2.hashCode());
}
};
// hashCodeOrder1 ์์ถ ์
static Comparator<Object> hashCodeOrder1 = comparingInt(Object::hashCode);
static Comparator<Object> hashCodeOrder2 = Comparator.comparingInt(o -> o.hashCode());
ํต์ฌ ์ ๋ฆฌ
์์๋ฅผ ๊ณ ๋ คํด์ผ ํ๋ ๊ฐ ํด๋์ค๋ฅผ ์์ฑํ๋ค๋ฉด ๊ผญ Comprable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ์ฌ, ๊ทธ ์ธ์คํด์ค๋ค์ ์ฝ๊ฒ ์ ๋ ฌํ๊ณ , ๊ฒ์ํ๊ณ , ๋น๊ต ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ์ปฌ๋ ์ ๊ณผ ์ด์ฐ๋ฌ์ง๋๋ก ํด์ผ ํ๋ค. compareTo ๋ฉ์๋์์ ํ๋์ ๊ฐ์ ๋น๊ตํ ๋ <์ > ์ฐ์ฐ์๋ ์ฐ์ง ๋ง์์ผ ํ๋ค. ๊ทธ ๋์ ๋ฐ์ฑ๋ ๊ธฐ๋ณธ ํ์ ํด๋์ค๊ฐ ์ ๊ณตํ๋ ์ ์ compre ๋ฉ์๋๋ Comprator ์ธํฐํ์ด์ค๊ฐ ์ ๊ณตํ๋ ๋น๊ต์ ์์ฑ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์.
๐ ๋๋์ .
equals, hashCode, toString, clone, compareTo ๋ฉ์๋๋ค์ ๊ท์ฝ, ์ฌ์ ์๋ฅผ ์ธ์ ํ๋์ง, ์ด๋ป๊ฒ ํ๋์ง์ ๋ํด ์ ์ ์๋ ์ฅ์ด์๋ค.
๊ฐ๋ฐํ๋ฉด์ ๋ง์ด ์ ํ ์ ์๋ ์์ญ์ด์๋ค ๋ณด๋ ์์ผ๋ก ์ฌ์ ์ํ ๋ ์ฐธ๊ณ ํ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
'Study > Effective Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Effective Java 3/E] 4์ฅ ํด๋์ค์ ์ธํฐํ์ด์ค (0) | 2023.05.23 |
---|---|
[Effective Java 3/E] 2์ฅ ๊ฐ์ฒด ์์ฑ๊ณผ ํ๊ดด (1) | 2023.04.30 |
[Effective Java 3/E] 1์ฅ ๋ค์ด๊ฐ๊ธฐ (0) | 2023.04.18 |