Growth-Collectors / effective-java

repository for effective java study
3 stars 2 forks source link

아이템 89. 인스턴스 수를 통제해야 한다면 readResolve보다는 열거 타입을 사용하라 #91

Open HanaHww2 opened 1 year ago

Tldkt commented 1 year ago

1. Serializable 인터페이스를 구현하는 예시

import java.io.Serializable;

public final class Elvis implements Serializable {

    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { }

    public static Elvis getINSTANCE() {
        return INSTANCE;
    }

    // readResolve 메서드를 정의한다.
    private Object readResolve() {
        // 싱글턴을 보장하기 위함!
        return INSTANCE;
    }
}

디폴트 직렬화 방법을 사용하면 인스턴스를 복원할 때마다 새로운 인스턴스가 생성

→ readResolve() 메서드 사용

역직렬화를 통해 객체가 복원될 때 호출

readResolve() 메서드

메서드 정의 후

import java.io.Serializable;

public final class Elvis implements Serializable {

    public static final Elvis INSTANCE = new Elvis();

    private Elvis() { }

    public static Elvis getINSTANCE() {
        return INSTANCE;
    }

    private Object readResolve() {
        return INSTANCE;
    }
}

INSTANCE 변수는 static으로 선언되어 있어서 클래스 로딩 시점에 생성됩니다. 따라서 readResolve() 메서드에서 반환하는 객체는 항상 INSTANCE 변수를 참조하게 됨

컴파일 타임에 어떤 인스턴스들이 있는지 알 수 없는 상황에는 열거 타입으로 표현하는 것이 불가능하므로 readResolve 방식을 써야 한다.

2. Transient 키워드

열거 타입(Enumeration Type)?

Elvis 인스턴스의 직렬화 형태는 아무런 실 데이터를 가질 필요가 없으니 모든 인스턴스 필드는 transient로 선언해야 한다.

Transient?

public class Person implements Serializable {
    private String name;
    private transient String password;

    public Person(String name, String password) {
        this.name = name;
        this.password = password;
    }

    // password 필드는 직렬화에서 제외됨
    public String toString() {
        return "Person [name=" + name + ", password=" + password + "]";
    }
}

Person 클래스의 password 필드에 transient 키워드가 적용되어 있으므로, 이 필드는 객체의 직렬화 대상에서 제외된다.

→ 즉, toString() 메서드에서 password 필드를 출력하더라도, 직렬화된 객체에는 password 필드가 포함되지 않게 되는 것

핵심 정리