오늘은 이펙티브 자바 중 "생성자나 열거 타입으로 싱글턴임을 보증하라
"에 대한 주제로 포스팅을 해보려고 합니다.
싱글턴 객체란 객체를 여러 개 생성하지 못하고 하나만 생성할 수 있게 만든 객체를 말합니다.
즉, 객체를 하나만 생성하는게 효율적일 경우 사용할 수 있습니다.
(밑의 코드들은 백기선님의 이펙티브 자바 완벽 공략 강의를 참고했습니다.)
public class Elvis{
public static final Elvis INSTANCE = new Elvis(); //객체를 미리 생성해 static 영역에 저장한다.
private Elvis(){} // 클라이언트에서 new 생성자로 객체를 생성하지 못하게 한다.
}
클라이언트 코드에서 #getInstace() 코드를 쓰면서 행위를 바꿀 수 있습니다.
public class Elvis{
private static final Elvis INSTANCE = new Elvis();
private Elvis(){}
public static Elvis getInstance(){
//return new Elvis();
return INSTANCE;
}
}
public static void main(String[] args){
//클라이언트 코드는 변경되지 않음.
Elvis.getInstace();
}
public class MetaElvis<T> {
private static final MetaElvis<Object> INSTANCE = new MetaElvis<>();
private MetaElvis() { }
public static <E> MetaElvis<E> getInstance() { return (MetaElvis<E>) INSTANCE; }
public void say(T t) {
System.out.println(t);
}
public static void main(String[] args) {
MetaElvis<String> elvis1 = MetaElvis.getInstance();
MetaElvis<Integer> elvis2 = MetaElvis.getInstance();
System.out.println(elvis1);
System.out.println(elvis2);
elvis1.say("hello");
elvis2.say(100);
}
}
public interface Singer {
void sing();
}
public class Elvis implements Singer {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { }
public static Elvis getInstance() { return INSTANCE; }
@Override
public void sing() {
System.out.println("my way~~~");
}
}
public class Concert {
public void start(Supplier<Singer> singerSupplier) {
Singer singer = singerSupplier.get();
singer.sing();
}
public static void main(String[] args) {
Concert concert = new Concert();
// start에 인자로 들어가는 Supplier가 getInstance와 일맥상통하다.
concert.start(Elvis::getInstance);
}
}
public enum Elvis{
INSTANCE;
public void sing(){
...
}
}
public static void main(String[] args){
try {
Constructor<Elvis> defaultConstructor = Elvis.class.getDeclaredConstructor();
//private 생성자에 접근을 가능하게 한다.
defaultConstructor.setAccessible(true);
//각기 다른 객체가 만들어 진다.
Elvis elvis1 = defaultConstructor.newInstance();
Elvis elvis2 = defaultConstructor.newInstance();
} catch (InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
public class Elvis{
public static final Elvis INSTANCE = new Elvis();
private static boolean created;
private Elvis() {
if (created) {
throw new UnsupportedOperationException("can't be created by constructor.");
}
created = true;
}
}
public static void main(String[] args) {
//직렬화, 저장
try (ObjectOutput out = new ObjectOutputStream(new FileOutputStream("elvis.obj"))) {
out.writeObject(Elvis.INSTANCE);
} catch (IOException e) {
e.printStackTrace();
}
//역직렬화, 읽기
try (ObjectInput in = new ObjectInputStream(new FileInputStream("elvis.obj"))) {
Elvis elvis3 = (Elvis) in.readObject();
//false를 리턴한다.
System.out.println(elvis3 == Elvis.INSTANCE);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
public class Elvis implements Serializable{
public static final Elvis INSTANCE = new Elvis();
private Elvis() {}
//이 메서드에서 INSTANCE를 리턴하게 한다.
private Object readResolve() {
return INSTANCE;
}
}
reference