item 89 hyowon - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki
[item 89]์ธ์คํด์ค ์๋ฅผ ํต์ ํด์ผ ํ๋ค๋ฉด readResolve๋ณด๋ค๋ ์ด๊ฑฐ ํ์ ์ ์ฌ์ฉํ๋ผ
์ต์ด ์ฝ๋
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis();
public void leaveTheBuilding() {...}
// ์ธ์คํด์ค ํต์ ๋ฅผ ์ํ readResolve
public Object readResolve() {
return INSTANCE;
}
}
- ์์ ๊ฐ์ ์ฑ๊ธํด์ readResolve ๋ฉ์๋๋ฅผ ์ฃผ์ด ์ธ์คํด์ค๋ฅผ ํต์ ํจ
- readResolve๋ ์ธ์คํด์ค๋ฅผ ์ญ์ง๋ ฌํ ํ ๊ฒฝ์ฐ์ ๊ธฐ์กด ์ญ์ง๋ ฌํํ ๋ ์ฌ์ฉํ๋ ์ธ์คํด์ค๋ฅผ ๋ถ๋ฌ์ ์ธ์คํด์ค๊ฐ ์ค์ง ํ๋๋ง ๋ง๋ค์ด์ง ์ ์๊ฒ ๋ณด์ฅํด์ฃผ๋ ์ญํ ์ ํ๋ค.
- readResolve ๊ธฐ๋ฅ์ ์ด์ฉํ๋ฉด readObject๊ฐ ๋ง๋ค์ด๋ธ ์ธ์คํด์ค๋ฅผ ๋ค๋ฅธ ๊ฒ์ผ๋ก ๋์ฒดํ ์ ์๋ค. ๋ฉ์๋๋ฅผ ์ ์ ํ ์ ์ํด ๋๋ค๋ฉด, ์ญ์ง๋ ฌํ๋ ์ ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ํ์ฌ ๋ฉ์๋๊ฐ ํธ์ถ๋๊ณ , ๊ธฐ์กด (์ง๋ ฌํ ํ๊ธฐ์ ์ธ) ๊ฐ์ฒด ์ฐธ์กฐ๊ฐ ๋ฐํ๋๋ค. ์ดํ ์ญ์ง๋ ฌํ๋ ์ ๊ฐ์ฒด๋ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋์์ด ๋๋ค.
- ๋ฌธ์ ์ ) readResolve๋ฅผ ์ธ์คํด์ค ํต์ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉํ๋ค๋ฉด ๊ฐ์ฒด ์ฐธ์กฐ ํ์ ์ธ์คํด์ค ํ๋๋ ๋ชจ๋ transient๋ก ์ ์ธํด์ผ ํ๋ค.
- ์ฆ, ์ฑ๊ธํด์ transient๊ฐ ์ ์ธ๋์ง ์์ ํ๋๊ฐ ์๋ค๋ฉด ๊ณต๊ฒฉ์ ์ฌ์ง๊ฐ ์๊ธด๋ค.
first draft
public class Elvis implements Serializable {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { }
private String[] favoriteSongs = {"Hound Dog", "Heartbreak Hotel"};
public void printFavorites() {
System.out.println(Arrays.toString(favoriteSongs));
}
private Object readResolve() {
return INSTANCE;
}
}
- ์ฑ๊ธํด์ด non_transient ํ ์ฐธ์กฐ ํ๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด, ๊ทธ ํ๋์ ๋ด์ฉ์ readResolve ๋ฉ์๋๊ฐ ์คํ๋๊ธฐ ์ ์ ์ญ์ง๋ ฌํ๋๋ค.
- ์ ์กฐ์๋ ์คํธ๋ฆผ์ ์จ์ ํด๋น ์ฐธ์กฐ ํ๋์ ๋ด์ฉ์ด ์ญ์ง๋ ฌํ๋๋ ์์ ์ ํด๋น ์ธ์คํด์ค์ ์ฐธ์กฐ๋ฅผ ํ์ณ์ฌ ์ ์๋ค.
first draft ๊ณต๊ฒฉ(๋๋ ํด๋์ค ๋ฐ ์คํ์ฝ๋)
public class ElvisStealer implements Serializable {
private static final long serialVersionUID = 0;
static Elvis impersonator;
private Elvis payload;
private Object readResolve() {
// resolve๋๊ธฐ ์ ์ Elvis ์ธ์คํด์ค์ ์ฐธ์กฐ๋ฅผ ์ ์ฅ
impersonator = payload;
// favoriteSongs ํ๋์ ๋ง๋ ํ์
์ ๊ฐ์ฒด๋ฅผ ๋ฐํ
return new String[] {"There is no cow level"};
}
}
public class ElvisImpersonator {
private static final byte[] serializedForm = new byte[]{
(byte) 0xac, (byte) 0xed, 0x00, 0x05, 0x73, 0x72, 0x00, 0x05,
// ์ฝ๋ ์๋ต
};
private static Object deserialize(byte[] sf) {
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(sf)) {
try (ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {
return objectInputStream.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
public static void main(String[] args) {
// ElvisStealer.impersonator ๋ฅผ ์ด๊ธฐํํ ๋ค์,
// ์ง์ง Elvis(์ฆ, Elvis.INSTANCE)๋ฅผ ๋ฐํ
Elvis elvis = (Elvis) deserialize(serializedForm);
Elvis impersonator = ElvisStealer.impersonator;
elvis.printFavorites(); // [Hound Dog, Heartbreak Hotel]
impersonator.printFavorites(); // [There is no cow level]
}
}
- ์ฑ๊ธํด์ ์๋ก ๋ค๋ฅธ ๋ ๊ฐ์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ์ ์์์ ์ฆ๋ช ํ ์ฝ๋
- ์ฐธ์กฐ๋ฅผ ํ์ณ์ ๋ค๋ฅธ ๊ฐ์ ๋ฃ์๋ค(impersonator)
- ๋ชจ๋ ํ๋๋ฅผ transient ์ ์ธ์ ํด์ ๊ณ ์น ์๋ ์์ง๋ง, Elvis๋ฅผ ์์ ํ๋์ง๋ฆฌ ์ด๊ฑฐ ํ์ ์ผ๋ก ๋ฐ๊พธ๋ ํธ์ด ๋ ๋ซ๋ค.
ํด๊ฒฐ์ฑ
public enum Elvis {
INSTANCE;
private String[] favoriteSongs =
{"Hound Dog", "Heartbreak Hotel"};
private void printFavourites() {
System.out.println(Arrays.toString(favoriteSongs));
}
}
- ์ง๋ ฌํ ๊ฐ๋ฅํ ์ธ์คํด์ค ํต์ ํด๋์ค๋ฅผ ์ด๊ฑฐ ํ์ ์ ์ด์ฉํด ๊ตฌํํ๋ฉด ์ ์ธํ ์์ ์ธ์ ๋ค๋ฅธ ๊ฐ์ฒด๋ ์กด์ฌํ์ง ์์์ ์๋ฐ๊ฐ ๋ณด์ฅํด์ค๋ค.
- ๊ณต๊ฒฉ์๊ฐ AccessibleObject.setAccessible ๋ฉ์๋์ ๊ฐ์ ํน๊ถ ๋ฉ์๋๋ฅผ ์ ์ฉํ์ ๋๋ ์์ธ๋ค. (์์์ ๋ค์ดํฐ๋ธ ์ฝ๋๋ฅผ ์ํํ ์ ์๋ ํน๊ถ์ ๊ฐ๋ก์ฑ ๊ณต๊ฒฉ์์๊ฒ๋ ๋ชจ๋ ๋ฐฉ์ด๊ฐ ๋ฌด๋ ฅํ๋๋ค.)
readResolve ๋ฐฉ์์ ์ธ์ ์ฌ์ฉ?
- ์ปดํ์ผํ์์๋ ์ด๋ค ์ธ์คํด์ค๋ค์ด ์๋์ง ์ ์ ์๋ ์ํฉ์ ์ด๊ฑฐ ํ์ ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ค.
readResolve ๋ฉ์๋์ ์ ๊ทผ์ ํ์ ์์ฑ
- final ํด๋์ค๋ผ๋ฉด private
- final์ด ์๋ ํด๋์ค๋ผ๋ฉด ๋ฉ์๋ ์ฌ์ฉ์ ํ๊ฐํ ๋ฒ์๋ฅผ ๊ณ ๋ คํด ์ ๊ทผ์ ํ์๋ฅผ ์์ฑํ๋ค. (private, package-private, protexted, public)
์ ๋ฆฌ
๋ถ๋ณ์์ ์งํค๊ธฐ ์ํด ์ธ์คํด์ค๋ฅผ ํต์ ํค์ผ ํ๋ค๋ฉด ์ด๊ฑฐ ํ์
์ ์ฌ์ฉํ๋ผ.
์ด๊ฑฐ ํ์
์ฌ์ฉ์ด ์ฌ์์น ์์ ์ํฉ์์ ์ง๋ ฌํ์ ์ธ์คํด์ค ํต์ ๋ฅผ ํ๋ ค๋ฉด
readResolve๋ฉ์๋๋ฅผ ์์ฑํด ๋ฃ๊ณ , ํด๋์ค์ ์ฐธ์กฐ ํ์
์ธ์คํด์ค ํ๋๋ฅผ transient๋ก ์ ์ธํ๋ค.