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
Last updated 12 months ago