DevLog ๐ถ
[์ดํฉํฐ๋ธ์๋ฐ] ์์ดํ 03. private ์์ฑ์๋ ์ด๊ฑฐ ํ์ ์ผ๋ก ์ฑ๊ธํด์์ ๋ณด์ฆํ๋ผ ๋ณธ๋ฌธ
[์ดํฉํฐ๋ธ์๋ฐ] ์์ดํ 03. private ์์ฑ์๋ ์ด๊ฑฐ ํ์ ์ผ๋ก ์ฑ๊ธํด์์ ๋ณด์ฆํ๋ผ
dolmeng2 2023. 4. 4. 23:29๐ฌ ์ดํฉํฐ๋ธ์๋ฐ ์์ดํ 3์ ์ฝ๊ณ ์ ๋ฆฌํ ๊ธ์ ๋๋ค.
โ๏ธ ์ฑ๊ธํด ์ธ์คํด์ค
์ธ์คํด์ค๋ฅผ ์ค์ง ํ๋๋ง ์์ฑํ ์ ์๋ ํด๋์ค. ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๋ฅผ ์ค์ผ ์ ์๊ณ , ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ์ ์๋ค.
๋ค๋ง, ๊ฒฐํฉ๋๊ฐ ์ฆ๊ฐํ๋ฉฐ ํด๋ผ์ด์ธํธ์ ํ ์คํธ๊ฐ ์ด๋ ค์์ง ์ ์๋ค๋ ์ ์ด ์กด์ฌํ๋ค.
-> ์ธ์คํด์ค๋ฅผ ๊ตฌํํด์ ๋ง๋ ์ฑ๊ธํด์ด ์๋๋ผ๋ฉด, ์ฑ๊ธํด ์ธ์คํด์ค๋ฅผ mock ๊ฐ์ฒด๋ก ๋์ฒดํ๊ธฐ๊ฐ ํ๋ค๊ธฐ ๋๋ฌธ์ด๋ค.
๐ฌ ์์ฑํ๋ ๋ฐฉ๋ฒ
1. ์์ฑ์๋ฅผ ๋ชจ๋ private๋ก ๋ง๋ค๊ณ , ์ธ์คํด์ค์ ์ ์ผํ ์ ๊ทผ์๋ฅผ public static์ผ๋ก ์์ฑํ๊ธฐ
public class Crew {
public static final Crew INSTANCE = new Crew();
private Crew() {
...
}
public void hello() {...}
}
์ด๋ ๊ฒ ๋๋ฉด, Crew ํด๋์ค๊ฐ ์์ฑ๋ ๋ static final ํ๋๋ก ์ธํด์ private ์์ฑ์๊ฐ ๋ฑ 1๋ฒ๋ง ํธ์ถ๋๋ค.
= ์ ์ฒด ์์คํ ์์ ํด๋น ์ธ์คํด์ค๋ ๋ฑ 1๊ฐ์์ ๋ณด์ฆํด์ค ์ ์๋ค.
2. ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋ ์ฌ์ฉํ๊ธฐ
public class Crew {
private static final Crew INSTANCE = new Crew();
private Crew() {
...
}
public static Crew getInstance() {
return INSTANCE;
}
public void hello() {...}
}
์ด์ ์ ์์ฑํ ํ๋๋ฅผ private๋ก ๋ณ๊ฒฝํ๊ณ , ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ ํตํด์ ํด๋น ํ๋๋ฅผ ์ ๊ทผํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๋ํ, ํด๋น ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ ํญ์ ๊ฐ์ ๊ฐ์ฒด์ ์ฐธ์กฐ๊ฐ์ ๋ฐํํ๊ฒ ๋๋ค.
๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ฅ๋จ์ ์ ๋น๊ตํด๋ณด์.
1๋ฒ → ํด๋์ค๊ฐ ์ฑ๊ธํด์์ API์ ๋ช ๋ฐฑํ๊ฒ ๋๋ฌ๋ธ๋ค. ๊ฐ๊ฒฐํ๋ค.
2๋ฒ → API์ ๋ณ๊ฒฝ์์ด ์ฑ๊ธํด์ด ์๋๋๋ก ๋ง๋ค ์ ์๋ค. (ํฉํฐ๋ฆฌ ๋ฉ์๋๊ฐ ํธ์ถํ๋ ์ค๋ ๋๋ณ๋ก ๋ค๋ฅธ ์ธ์คํด์ค๋ฅผ ๋๊ฒจ์ค๋ค๋ ์ง…?), ์ ๋ค๋ฆญ ์ฑ๊ธํด ํฉํฐ๋ฆฌ๋ก ๋ง๋ค๊ฑฐ๋, ์ ์ ํํฐ๋ฆฌ ๋ฉ์๋ ์ฐธ์กฐ๋ฅผ ๊ณต๊ธ์๋ก ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. (ex. Supplier)
๐ก ์ ๋ค๋ฆญ ์ฑ๊ธํด ํฉํฐ๋ฆฌ๋ ์ถํ ์๊ฐ๋๊ฒ ์ง๋ง, ๊ฐ๋ตํ๊ฒ ์ค๋ช ํ๋ฉด ์์ฒญ์ผ๋ก ๋ค์ด์จ ํ์ ๋งค๊ฐ๋ณ์์ ๋ง๊ฒ, ๊ทธ ๊ฐ์ฒด์ ํ์ ์ ๋ฐ๊พธ์ด์ฃผ๋ ์ ์ ํฉํฐ๋ฆฌ๋ฅผ ์์ฑํด์ฃผ๋ ๊ฒ์ ์๋ฏธํ๋ค.
// ImmutableCollections.java
static <E> Set<E> emptySet() {
return (Set<E>) SetN.EMPTY_SET;
}
๊ทธ๋ฅ ์ ๋ค๋ฆญ + ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ผ๊ณ ์๊ฐํ๋ฉด ํธํ๋ค :D
๐ฌ ์ง๋ ฌํ ๊ด์
์ฑ๊ธํด ํด๋์ค๋ฅผ ์ง๋ ฌํํ๋ ๊ฒ์ ์ฃผ์๋ฅผ ํด์ผ ํ๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์ฑ๊ธํด ํด๋์ค๋ ํ๋์ ์ธ์คํด์ค๋ง ๊ฐ์ง๊ณ ์๋ค. ํ์ง๋ง, ํด๋น ์ธ์คํด์ค๋ฅผ ์ง๋ ฌํํ ๋ค, ๋ค์ ์ญ์ง๋ ฌํ๋ฅผ ํตํด ๋ณต์ํ๊ฒ ๋๋ค๋ฉด ํด๋น ํด๋์ค์ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๊ฐ ๋๋ค.
์ด๋ ๊ฒ ๋๋ฉด, ์ฑ๊ธํด ํด๋์ค๋ 'ํ๋์ ์ธ์คํด์ค๋ง ์์ฑํ๋ค'๋ผ๋ ๊ฐ๋ ๊ณผ ์ผ์นํ์ง ์๊ฒ ๋๋ค.
๊ทธ๋์, ์ฑ๊ธํด ํด๋์ค์ ์ง๋ ฌํ๋ฅผ ์ํด์๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
๋ง์ฝ, ์ธ์คํด์ค ํ๋๊ฐ ์กด์ฌํ๋ค๋ฉด ๋ชจ๋ ์ธ์คํด์ค ํ๋๋ฅผ transient๋ก ์ค์ ํ์ฌ ์ง๋ ฌํ์์ ์ ์ธ์ํค๋ ๊ฒ์ด๋ค.
public class Singleton implements Serializable {
private static final long serialVersionUID = 1L;
private transient String name;
private static final Singleton instance = new Singleton("Test");
private Singleton(final String name) {
this.name = name;
}
public static Singleton getInstance() {
return instance;
}
@Override
public String toString() {
return "Singleton{" +
"name='" + name + '\'' +
'}';
}
}
transient ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ํ๋๊ฐ ์์ฒด๋ ์ ์ง๋์ง๋ง, ๋ด๋ถ์ ์ผ๋ก null ๊ฐ์ด ๋์ ๋๋ค.
์ฆ, ์์ฑํ instance์ ๋ํด ์ญ์ง๋ ฌํ ์ ๊ฒฐ๊ณผ๊ฐ์ด null์ด ๋๋ ๊ฒ์ด๋ค.
๋ง์ฝ, transient๋ฅผ ๋ถ์ด์ง ์์ ์ํ๋ก ์ง๋ ฌํ๋ฅผ ํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
public class Main {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
// ์ง๋ ฌํ๋ฅผ ์งํํ๋ค.
try (FileOutputStream fileOut = new FileOutputStream("singleton.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
out.writeObject(singleton);
} catch (IOException i) {
i.printStackTrace();
}
// ์ญ์ง๋ ฌํ๋ฅผ ์งํํ๋ค.
Singleton deserializedSingleton;
try (FileInputStream fileIn = new FileInputStream("singleton.ser");
ObjectInputStream in = new ObjectInputStream(fileIn)) {
deserializedSingleton = (Singleton) in.readObject();
} catch (IOException | ClassNotFoundException i) {
i.printStackTrace();
return;
}
// ์ถ๋ ฅ
System.out.println(deserializedSingleton.toString());
}
}
transient๋ฅผ ๋ถ์ด์ง ์์์ ๋๋ ๋ค์๊ณผ ๊ฐ์ด null์ด ์๋ ์ค์ ๊ฐ์ด ๋ค์ด๊ฐ๋ค.
๋ฐ๋ฉด์, transient๋ฅผ ๋ถ์ด๋ฉด ์์ ๊ฐ์ด null์ด ๋ค์ด๊ฐ๋ค.
๋ค๋ง, transient ํค์๋๋ ์ธ์คํด์ค ๋ณ์์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ค.
์ ์ฝ๋์์ instance์ ๊ฒฝ์ฐ static ํค์๋๋ฅผ ์ฌ์ฉํ์๊ธฐ ๋๋ฌธ์ ์ธ์คํด์ค์ ๋ฌด๊ดํ๊ฒ ํด๋์ค ์์ฒด์ ์ํ๊ฒ ๋๋ค.
์ฆ, ํด๋์ค ์์ฒด๊ฐ ์ง๋ ฌํ๋๋ฉด์ ์ญ์ง๋ ฌํ ๊ณผ์ ์์ getInstance๊ฐ ์๋ ์ ์ฅ๋ ์ธ์คํด์ค๊ฐ ๋ณต์๋๋ฉฐ, ๊ธฐ์กด์ ์ฑ๊ธํด ์ธ์คํด์ค์ ๋ค๋ฅธ ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ฒ ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์, ์ถ๊ฐ์ ์ผ๋ก readResolve()๋ฅผ ์ฌ์ ์ ํด์ผ ํ๋ค.
boolean result = singleton == deserializedSingleton;
System.out.println("singleton == deserializedSingleton : " + result);
์ค์ ๋ก ์์ ์ฝ๋๋ฅผ ๋๋ ค๋ณด๋ฉด, false๊ฐ ๋์จ๋ค.
public class Singleton implements Serializable {
private static final long serialVersionUID = 1L;
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
protected Object readResolve() {
return instance;
}
}
๋ฐ๋ฉด์ readResolve() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด, ์ญ์ง๋ ฌํ ๊ณผ์ ์์ ๋ง๋ค์ด์ง ์ธ์คํด์ค ๋์ ์ ๊ธฐ์กด์ ์์ฑ๋ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋๋ก
๋ง๋ค์ด์ ํด๋น ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ๋๋ก ๋ง๋ค ์ ์๋ค.
๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด, ์ด๋ ๊ฒ true๊ฐ ๋ฐํ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค!
๐ฌ ์ readResolve()๋ฅผ ์ฌ์ ์ํ๋ฉด ๋๋ ๊ฑธ๊น?
๊ถ๊ธํด์ ๋ฉ์๋ ๋ด๋ถ๋ฅผ ์กฐ๊ธ ๊น๋ดค๋ค.
try (FileInputStream fileIn = new FileInputStream("singleton.ser");
ObjectInputStream in = new ObjectInputStream(fileIn)) {
deserializedSingleton = (Singleton) in.readObject(); // Here!
...
์ ์ฝ๋์์ readObject()์ ๋ด๋ถ ๊ตฌํ์ ์ดํด๋ณด์.
์ด๋ ๊ฒ bypass ํ๋ ๋ฉ์๋๊ฐ ์ ์๋์ด ์๋๋ฐ, ๋ ๋ฐ๋ผ๊ฐ๋ณด์.
์ด ๋ฉ์๋์์ ์ค๊ฐ์ ์๋ readObject0 ๋ฉ์๋๋ฅผ ํ๊ณ ๋ค์ด๊ฐ๋ณด์!
๊ทธ๋ผ ์ฌ๊ธฐ์ object case์ ๋ํด readOrdinaryObject()๋ผ๋ ๋ฉ์๋๋ฅผ ํธ์ถํ๋๋ฐ!
๋ค์ด๊ฐ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด readResolve() ๋ฉ์๋๊ฐ ์๋์ง ํ์ธ์ ํ๊ณ , ์กด์ฌํ๋ ๊ฒฝ์ฐ์ invoke๋ฅผ ํตํด์ ํธ์ถํด์ฃผ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.์ค์ ๋ก invokeReadResolve() ๋ฉ์๋๋ฅผ ๋ณด๋ฉด ์๋์ ๊ฐ๋ค. (์ด๋์ ๋ฉ์๋์ ๋ค์ด๋ฐ์ด ์ค์ํ๋ค๋ ๊ฒ์ ๋ค์ ๊นจ๋ซ๋๋ค ๐)
์๋ฐ ์์ผ๋ก ๋ด๋ถ์์ invoke๋ฅผ ํตํด ์ฐ๋ฆฌ๊ฐ ์์ฑํ ์ฝ๋๋ฅผ ํธ์ถํด์ฃผ๋ ๊ฒ ๊ฐ๋ค! ใ ใ
์ถ๊ฐ์ ์ผ๋ก ์ฑ ์์๋ ์ฑ๊ธํด์ ์์ฑ ๋ฐฉ๋ฒ์ผ๋ก enum์ ์๊ฐํ๋ค.
enum์ ๊ฒฝ์ฐ JVM์ด ํ๋์ ์ธ์คํด์ค๋ก ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ด๋ค.
public enum Crew {
INSTANCE;
public void hello() {...}
}
๋ํ, enum์ ๊ฒฝ์ฐ ๊ธฐ๋ณธ์ ์ผ๋ก Serializableํ๋ค. enum์ ๊ฒฝ์ฐ ์ง๋ ฌํ๋ฅผ ํ๊ฒ ๋๋ฉด ObjectOutputStream์์ name()์ return ๊ฐ์ ์ฌ์ฉํ๋ฉฐ, ์ญ์ง๋ ฌํ ์์๋ valueOf๋ฅผ ํตํด enum์ constant ๊ฐ์ ๊ฐ์ ธ์จ๋ค๊ณ ํ๋ค.
ํ์ง๋ง, readResolve ๊ฐ์ ๋ฉ์๋๋ฅผ ํตํด ๋ณ๋๋ก ์ปค์คํ ์ ๋ถ๊ฐ๋ฅํ๋ฉฐ, serialVersionUID์ ๊ฒฝ์ฐ 0L๋ก ๊ณ ์ ์ด ๋์ด์๋ค.
์ฝ๋๋ก ํ์ธํด๋ณด์!
case๊ฐ ์น์ ํ๊ฒ enum์ ๋ํด์ ๋๋์ด์ ธ์๋ค ใ ใ (์ญ์ง๋ ฌํ ์ ์ฌ์ฉํ๋ readObject() ๋ฉ์๋๋ฅผ ์๊น์ฒ๋ผ ๊น๋ณธ ๊ฒ์ด๋ค.)
์ฌ๊ธฐ์ Enum.valueOf๋ฅผ ํตํด์ result๋ฅผ ๋ด์์ฃผ๋ ๊ฒ์ ๋ณผ ์ ์๋ค!
์ง๋ ฌํ ๊ณผ์ ๋ ์ดํด๋ณด์.
writeObject์ ๋ฉ์๋ ์ค์์ writeObject0๋ฅผ ๋ค์ด๊ฐ๋ณด์!
๊ทธ๋ผ Enum ํ์ ์ ๋ํด์ writeEnum์ด๋ผ๋ ๋ฉ์๋๋ฅผ ํธ์ถํ๊ฒ ๋๋ฉฐ,
๋ด๋ถ์ ์ผ๋ก en.name()์ ํตํด์ writeString์ ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค!
์ฑ ์์ ๋๋ถ๋ถ์ ์ด๊ฒ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ํ๋๋ฐ, ๋ง์ฝ ๋ง๋ค๋ ค๋ ๊ฐ์ฒด๊ฐ ์์์ ํด์ผ ๋๋ค๋ฉด ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ค. (enum ์์ฒด๋ ์ถ๊ฐ ์์์ด ์ ๋๋๊น)
์ฑ ๋ด์ฉ์ ๊ฐ๊ฒฐํ๋ฐ ์ง๋ ฌํ ๋ถ๋ถ์ ๊ณต๋ถํ๋ค ๋ณด๋ ์๊ฐ๋ณด๋ค ์ ๋ฆฌํ๋ ๋ฐ ๋ ๊ฑธ๋ ธ๋ค ๐ฆ
๊ทธ๋๋ ์ฝ๋ ๊น๋ณด๋ ๊ฑด ํญ์ ์ฌ๋ฐ๋ค ใ ใ ์ดํฉํฐ๋ธ ๋จ์ ๊ฒ๋ ์ผ๋ฅธ ์ ๋ฆฌํด์ผ์ง...