public class Elvis{
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public void leaveTheBuilding() { ... }
}
싱글턴 패턴이 언부에 “implements Serializable”을 붙히면 더이상 싱글턴 클래스가 아니다.
· 해당 객체는 클래스가 초기화 될 당시에 만들어지는 객체와 같은 객체가 아니다.
· readResolve를 이용하면 readObject가 만들어낸 객체를 다른 것으로 대체할 수 있다.
역직렬화할 객체의 클래스에 제대로 선언된 readResolve가 정의 되어 있을 경우, 역직렬화가 끝나서 만들어진 객체에 대해 이 메서드가 호출된다.
· readReolve호출이 끝나고나면 readObject가 만든 객체에 대한 참조는 사라지므로, 바로 쓰레기 수집이 가능해 진다.
// 개체 통제를 위해 readResolve를 활용한 사례
private Object readResolve(){
// 유일한 Elvis 객체를 반환하고, Elvis를 가장한 새 객체는 바로 쓰레기 수집되도록 함
return INSTANCE;
}
개체 통제를 위해 readResolve를 활용할 때는, 객체 참조 자료형으로 선언된 모든 객체 필드를 반드시 transient로 선언해야 한다.
· transient를 안할 경우 MutablePeriod공격과 거의 비슷한 기술을 이용하여 readResolv 메서드가 실행되기 전에 역직렬화된 객체에 대한 참조를 가로챌 수 있게 된다.
· 싱글턴 객체에 비-transient필드가 있을 경우, 해당 필드 내용은 readResolve 메서드가 실행되기 전에 역직렬화될 것이다. 주의깊게 조작된 바이트 스트림을 이용하면 객체에 참조 필드의 내용이 역으로 직렬화 되는 순간에 readObject가 반환하는 원래 객체의 참조를 “steal”할 수 있게 된다.
· 직렬화 가능한 객체통제 클래스를 enum으로 구현한다면, 선언된 상수 이외의 다른 객체는 존재할 수 없다는 확실한 보장이 생긴다. (JVM이 해주는 보장이므로 믿을 수 있다.)
public Enum Elvis{
INSTANCE;
private String[] favoriteSongs =
{"HOUND DOGS" , "Heartbreak Hotel"};
private void printFavorites(){
sysout(Arrays.toString(favoriteSongs));
}
}
결론
· 개체수와 관련된 불변식을 강제하고 싶을 때는 enum을 이용하라
· 직렬화 가능하며 개체수를 통제하는 클래스가 필요하다면 반드시 readResolve메서드를 구현하며, 클래스의 모든 객체필드는 모두 기본자료형이 아니면 transient로 선언하라
'IT > Programming' 카테고리의 다른 글
<Effective Java> RULE 75 사용자 지정 직렬화 형식을 사용하면 좋을 지 따져 보라 (0) | 2023.04.25 |
---|---|
<Effective Java> RULE 76 readObject메서드는 방어적으로 구현하라 (0) | 2023.04.25 |
<Effective Java> RULE 78 직렬화된 객체 대신 직렬화 프록시를 고려해 보라 (1) | 2023.04.25 |
[JAVA] helloworld print 예제 (0) | 2023.04.25 |
[JAVA] println, print 예제 (0) | 2023.04.25 |