HihoBookStudy / EffectiveJava

이펙티브 자바 북스터디입니다.
1 stars 0 forks source link

[Item 15] 배열 문제에 대한 해결책 질문 #25

Closed ForteEscape closed 2 months ago

ForteEscape commented 2 months ago

Q. 책(P.99)에서 다음과 같은 내용을 설명하며, 그 대안으로 2가지의 해결책을 제시하고 있습니다.

길이가 0이 아닌 배열은 모두 변경 가능하니 주의하자. 클래스에서 public static final 배열 필드를 두거나, 이 필드를 반환하는 접근자 메서드(getter, setter)를 제공하면 안된다. (중략) 해결책은 두 가지다. 첫 번째는 배열의 접근자를 private으로 만들고, public 불변 리스트를 추가하는 것이다. 두 번째는 배열을 private으로 만들고, 그 복사본을 반환하는 public 메서드를 제공하는 방법이다.

private static final Something[] PRIVATE_VALUES = {...};

// solution1.
public static final List<Something> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));

// solution2.
public static final Thing[] values() {
    return PRIVATE_VALUES.clone();
}
IAGREEBUT commented 2 months ago

첫 번째는 어떤 상황에서 solution1이 더 사용하기 편리하고, 그렇지 않은지 어떤 상황에서 solution2가 사용하기 편리한지에 대해 질문 드립니다. 두 번째는 성능의 고려라는 말이 적혀 있는데 두 방식의 성능 차이가 유의미한지. 그렇다면 왜 성능 차이가 나며, 어떤 상황에서 발생할 수 있는지에 대해 질문 드립니다.

  1. 두가지 방식의 특징(차이점)

[1]배열의 접근자를 private으로 만들고, public 불변 리스트를 추가하는 방법

[2] public배열을 private으로 만들고 해당 복사본을 반환하는 public method를 추가 (방어적 복사)

  1. 어느상황에서 사용이 적절한지

보편적으로 복사가 발생해야하는 두가지 상황 1) 생성자의 인자로 객체를 받아서 내부 필드를 초기화 하고자 할 때 → 생성자의 인자로 객체를 받아서 내부를 초기화 한 후, 생성자에서 사용한 인자 객체가 변경되었다고 하자. 이 상황에서도 이미 생성된 객체의 내부 필드는 변경되어서는 안된다 ⇒ 방어적 복사가 적절한 상황

2) getter 메소드에서 내부의 객체를 반환할 때 → 클라이언트가 getter메소드로 받은 객체를 어떻게 활용하고자 하는지에 따라 두가지 모두 선택 가능하다.

**성능차이에 관하여.. (이 책에서 언급하고 있는 성능 차이라는 것이 정확하게 어느면에서 성능을 말하는지는 정확히 모르겠습니다) 하지만, 방어적 복사의 여러가지 이점에도 불구하고, 방어적 복사에는 성능저하 이슈가 따릅니다. (아이템50 - 적시에 방어적 복사본을 만들라) 복사시 마다 새로운 객체를 생성해내기 때문입니다. 따라서 위의 예시처럼 원본배열이 변경될 일이 없는 상황에서도 unmodifiable대신 방어적 복사를 사용하게 되면, 의미없이 같은 내용을 보유한 객체가 여러개 생성되어 unmodifiable방식에 비하여 성능 저하를 유발할 수 있을 것으로 예상됩니다.