private ์์ฑ์๋ ์ด๊ฑฐ ํ์
์ผ๋ก ์ฑ๊ธํด์์ ๋ณด์ฆํ๋ผ
์ฑ๊ธํด์ด๋ ์ธ์คํด์ค๋ฅผ ์ค์ง ํ๋๋ง ์์ฑํ ์ ์๋ ํด๋์ค๋ก, ์ฌ์ฉํ ์๋ก๋ ํจ์์ ๊ฐ์ ๋ฌด์ํ ๊ฐ์ฒด๋ ์ค๊ณ์ ์ ์ผํด์ผ ํ๋ ์์คํ
์ปดํฌ๋ํธ๊ฐ ์๋ค.
์ฑ๊ธํด์ ๋ง๋๋ ๋ฐฉ๋ฒ
์ฑ๊ธํด์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ณดํต ๋ ๊ฐ์ง ๋ฐฉ์์ด ์๋ค.
1. public static final ํ๋ ๋ฐฉ์
์ ์ฝ๋์์ ๋ณผ ์ ์๋ฏ์ด static final
ํ๋์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค์ด public์ผ๋ก ์ ์ธํ๊ณ , ์์ฑ์๋ฅผ private์ผ๋ก ์ ์ธํ์ฌ ์ธ๋ถ์์ ์ธ์คํด์ค๋ฅผ ์์ฑํ์ง ๋ชปํ๋๋ก ํ๋ค. ์ด ๋ฐฉ์์ ํด๋น ํด๋์ค๊ฐ ์ฑ๊ธํด์์ด API์ ๋ช
๋ฐฑํ ๋๋ฌ๋๋ ์ฅ์ ์ด ์๋ค.
Copy class Ogu {
public static final Ogu INSTANCE = new Ogu();
private Ogu() {
}
public void something() {
System.out.println("something");
}
}
2. ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋ ๋ฐฉ์
์๋ ์ฝ๋์์ ๋ณผ ์ ์๋ฏ์ด static
ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ public์ผ๋ก ์ ์ธํ๊ณ , ์์ฑ์๋ฅผ private์ผ๋ก ์ ์ธํ์ฌ ์ธ๋ถ์์ ์ธ์คํด์ค๋ฅผ ์์ฑํ์ง ๋ชปํ๋๋ก ํ๋ค.
Copy class Ogu {
private static final Ogu INSTANCE = new Ogu();
private Ogu() {
}
public static Ogu getInstance() {
return INSTANCE;
}
public void something() {
System.out.println("something");
}
}
์ด ๋ฐฉ์์ 1๋ฒ์ ๋ฐฉ๋ฒ๊ณผ ๋ค๋ฅด๊ฒ ์๋์ ๊ฐ์ ์ฅ์ ์ด ์๋ค. ๋ง์ฝ ์๋ ์ฅ์ ๋ค์ด ํ์ํ์ง ์๋ค๋ฉด 1๋ฒ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
API๋ฅผ ๋ฐ๊พธ์ง ์๊ณ ๋ ์ฑ๊ธํด์ด ์๋๊ฒ ๋ณ๊ฒฝ ๊ฐ๋ฅ
Copy class Ogu {
private static boolean useSingleton = true; // ์ฑ๊ธํด ์ฌ์ฉ ์ฌ๋ถ ํ๋๊ทธ ๊ฐ
private Ogu() {
}
public static Ogu getInstance() {
if (useSingleton) {
return SingletonHolder.INSTANCE;
} else {
return new Ogu();
}
}
public void something() {
System.out.println("something");
}
// ์ฑ๊ธํค ์ธ์คํด์ค๋ฅผ ๋ณด์ ํ ๋ด๋ถ ํด๋์ค
private static class SingletonHolder {
private static final Ogu INSTANCE = new Ogu();
}
}
class Main {
public static void main(String[] args) {
Ogu singletonInstance = Ogu.getInstance();
singletonInstance.something();
// ์ฑ๊ธํด ์ฌ์ฉ ์ฌ๋ถ ํ๋๊ทธ ๊ฐ์ false๋ก ๋ณ๊ฒฝ
Ogu.useSingleton = false;
Ogu nonSingletonInstance = Ogu.getInstance(); // ์๋ก์ด ์ธ์คํด์ค ์์ฑ
nonSingletonInstance.something();
}
}
์ ์ ํฉํฐ๋ฆฌ๋ฅผ ์ ๋ค๋ฆญ ์ฑ๊ธํด ํฉํฐ๋ฆฌ๋ก ๋ง๋ค ์ ์์
Copy class SingletonFactory<T> {
private final Supplier<T> supplier;
private T instance;
private SingletonFactory(Supplier<T> supplier) {
this.supplier = supplier;
}
public static <T> SingletonFactory<T> create(Supplier<T> supplier) {
return new SingletonFactory<>(supplier);
}
public T getInstance() {
if (instance == null) {
instance = supplier.get();
}
return instance;
}
}
class Main {
public static void main(String[] args) {
// Supplier๋ฅผ ์ฌ์ฉํ์ฌ String ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ SingletonFactory๋ฅผ ์์ฑ
SingletonFactory<String> stringFactory = SingletonFactory.create(() -> "Hello, Singleton!");
// ์ฑ๊ธํด ์ธ์คํด์ค๋ฅผ ์ป๊ณ ์ฌ์ฉ
String singletonString = stringFactory.getInstance();
System.out.println(singletonString); // Hello, Singleton!
// Supplier๋ฅผ ์ฌ์ฉํ์ฌ Integer ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ SingletonFactory๋ฅผ ์์ฑ
SingletonFactory<Integer> integerFactory = SingletonFactory.create(() -> 42);
// ์ฑ๊ธํด ์ธ์คํด์ค๋ฅผ ์ป๊ณ ์ฌ์ฉ
Integer singletonInteger = integerFactory.getInstance();
System.out.println(singletonInteger); // 42
}
}
์ ์ ํฉํฐ๋ฆฌ์ ๋ฉ์๋ ์ฐธ์กฐ๋ฅผ ๊ณต๊ธ์(supplier)๋ก ์ฌ์ฉํ ์ ์์
Copy class Ogu {
private static final Ogu INSTANCE = new Ogu();
private Ogu() {
}
public void something() {
System.out.println("something");
}
public static Ogu getInstance() {
return INSTANCE;
}
}
class Main {
public static void main(String[] args) {
// ์ ์ ํฉํ ๋ฆฌ์์ ๋ฉ์๋ ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ์ฌ ๊ณต๊ธ์๋ก ์ฌ์ฉ
Supplier<Ogu> oguSupplier = Ogu::getInstance;
// ๊ณต๊ธ์๋ฅผ ์ฌ์ฉํ์ฌ ์ธ์คํด์ค๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ฌ์ฉ
Ogu instance1 = oguSupplier.get();
instance1.something();
Ogu instance2 = oguSupplier.get();
instance2.something();
}
}
3. ์์๊ฐ ํ๋์ธ ์ด๊ฑฐ ํ์
๋ฐฉ์
์ด๊ฑฐ ํ์
์ ์ฑ๊ธํด์ ๋ง๋๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ผ๋ก, ์ง๋ ฌํ ๋ฌธ์ ๋ ์๋์ผ๋ก ์ฒ๋ฆฌ๋๊ณ ๋ฆฌํ๋ ์
๊ณต๊ฒฉ์๋ ์์ ํ๊ฒ ๋ณด์ฅ๋๋ค.
Copy enum Ogu {
INSTANCE;
public void something() {
System.out.println("something");
}
}
๋จ, ๋ง๋ค๋ ค๋ ์ฑ๊ธํด์ด Enum ์ธ์ ํด๋์ค๋ฅผ ์์ํด์ผ ํ๋ค๋ฉด ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
๋๋ฌธ์ ์์์ ํด์ผํ๋ ์ํฉ์ด ์๋๋ผ๋ฉด ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข๋ค.
์ฑ๊ธํด ํด๋์ค๋ฅผ ๋ง๋ค ๋ ์ฃผ์ํ ์
์์์๋ ์ธ๊ธํ๋ฏ์ด 1, 2๋ฒ ํจํด์ผ๋ก ๋ง๋ค๊ฒ ๋๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก ์ฑ๊ธํด ์ธ์คํด์ค๋ฅผ ๋ณด์ฅํ ์ ์์ง๋ง, ์๋ ๋ ๊ฐ์ง ์ํฉ์์๋ ์ฑ๊ธํด์ด ๊นจ์ง ์ ์๋ค.
๋๋ฌธ์ ์๋ฒฝํ๊ฒ ์ฑ๊ธํด์ ๋ณด์ฅํ๋ ค๋ฉด ์ง๋ ฌํ(Serialization)์ ๋ฆฌํ๋ ์
(Reflection)์ ๊ณ ๋ คํด์ผ ํ๋ค.
๋ฆฌํ๋ ์
์ ํตํ ์์ธ
๋ฆฌํ๋ ์
์ ์ด์ฉํ๋ฉด private ์์ฑ์๋ฅผ ํธ์ถํ ์ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ๊ณต๊ฒฉ์ ๋ฐฉ์ดํ๊ธฐ ์ํด์๋ ์์ฑ์์์ ๋ ๋ฒ์งธ ๊ฐ์ฒด๊ฐ ์์ฑ๋๋ ค๊ณ ํ ๋ ์์ธ๋ฅผ ๋ฐ์ ์ํค๋ ๋ฐฉ์ด ์ฝ๋๋ฅผ ๋ฃ์ด์ผ ํ๋ค.
Copy class ReflectionExample {
public static void main(String[] args) {
try {
// Ogu ํด๋์ค์ ๋น๊ณต๊ฐ ์์ฑ์ ๊ฐ์ ธ์ค๊ธฐ
Constructor<Ogu> constructor = Ogu.class.getDeclaredConstructor();
// ๋น๊ณต๊ฐ ์์ฑ์์ ์ ๊ทผํ ์ ์๋๋ก ํ์ฉ
constructor.setAccessible(true);
// ๋ฆฌํ๋ ์
์ ์ฌ์ฉํ์ฌ Ogu์ ์ธ์คํด์ค ์์ฑ
Ogu oguInstance = constructor.newInstance();
// ์์ฑํ ์ธ์คํด์ค๋ก Ogu์ ๋ฉ์๋ ํธ์ถ
oguInstance.something(); // something
// ๋ค๋ฅธ ์ธ์คํด์ค์ธ์ง ํ์ธ
System.out.println("Original INSTANCE: " + Ogu.INSTANCE); // Ogu@279f2327
System.out.println("Reflectively created instance: " + oguInstance); // Ogu@2ff4acd0
System.out.println("Are both instances same? " + (Ogu.INSTANCE == oguInstance)); // false
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Ogu {
public static final Ogu INSTANCE = new Ogu();
private Ogu() {
// if (INSTANCE != null) {
// throw new RuntimeException("Already initialized");
// }
}
public void something() {
System.out.println("something");
}
}
์์ฑ์์ ๋ฐฉ์ด ์ฝ๋ ์ฃผ์์ ํด์ ํ๋ฉด ์๋์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด์ ๋ ๋ฒ์งธ ๊ฐ์ฒด๊ฐ ์์ฑ๋์ง ์๋๋ค.
Copy java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at ReflectionExample.main(test.java:14)
Caused by: java.lang.RuntimeException: Already initialized
at Ogu.<init>(test.java:34)
... 6 more
์ง๋ ฌํ๋ฅผ ํตํ ์์ธ
1, 2๋ฒ ๋ฐฉ์์ผ๋ก ๋ง๋ ์ฑ๊ธํด ํด๋์ค๋ ์ง๋ ฌํํ ๋ค์ ์ญ์ง๋ ฌํํ๋ฉด ํด๋น ๊ฐ์ฒด์ ์ ์ธ์คํด์ค๊ฐ ์์ฑ๋๋ ๋ฌธ์ ๊ฐ ์๋ค.
๋๋ฌธ์ ์ฑ๊ธํด ํด๋์ค๋ฅผ ์ง๋ ฌํํ๊ณ ์ญ์ง๋ ฌํํ ๋๋ง๋ค ์๋ก์ด ์ธ์คํด์ค๊ฐ ์์ฑ๋๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ readResolve
๋ฉ์๋๋ฅผ ์ ๊ณตํด์ผ ํ๋ค.
readResolve
๋ฉ์๋๋ Java์ ์ญ์ง๋ ฌํ ํ๋ก์ธ์ค ์ค์ ์ฌ์ฉ๋๋ ํน์ ๋ฉ์๋๋ก, ๊ตฌํํด์ผ ํ๋ ์ธํฐํ์ด์ค ๋ฉ์๋๊ฐ ์๋ ์ญ์ง๋ ฌํ ๋์์ ํด๋์ค์์ ์ ํ์ ์ผ๋ก ์ ์ํ ์ ์๋ ๋ฉ์๋์ด๋ค.
Copy class Singleton implements Serializable {
public static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
// ๊ธฐ์กด ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋๋ก ์ ์ํ์ฌ, ์ญ์ง๋ ฌํ ์ค์ ์๊ธด ์๋ก์ด ์ธ์คํด์ค๋ GC์ ์ํด ์ ๊ฑฐ๋จ
private Object readResolve() {
return INSTANCE;
}
}
class Main {
public static void main(String[] args) {
try {
// ์ฑ๊ธํด ๊ฐ์ฒด ์ง๋ ฌํ
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singleton.ser"));
out.writeObject(Singleton.getInstance());
out.close();
// ์ฑ๊ธํด ๊ฐ์ฒด ์ญ์ง๋ ฌํ
ObjectInputStream in = new ObjectInputStream(new FileInputStream("singleton.ser"));
Singleton deserializedSingleton = (Singleton) in.readObject();
in.close();
// ์ฑ๊ธํด ๊ฐ์ฒด์ ๋์ผ์ฑ ํ์ธ
System.out.println(Singleton.getInstance()); // Singleton@27fa135a
System.out.println(deserializedSingleton); // Singleton@27fa135a
System.out.println(Singleton.getInstance() == deserializedSingleton); // true
} catch (Exception e) {
e.printStackTrace();
}
}
}
๋ง์ฐฌ๊ฐ์ง๋ก readResolve
๋ฉ์๋ ์ฃผ์์ ํด์ ํ๋ฉด ์๋ก์ด ์ธ์คํด์ค๊ฐ ๋ฐํ๋์ด ์๋์ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ๋๋ค.
Copy Singleton@27fa135a
Singleton@6d5380c2
false