작지만 꾸준한 반복

방어적 복사가 있으면 공격적 복사도 있나? 본문

공부기록/Java

방어적 복사가 있으면 공격적 복사도 있나?

iamjooon2 2023. 3. 6. 21:50

우아한테크코스에서 페어프로그래밍을 진행하며 얻을 수 있는 큰 장점은

페어의 지식을 흡수할 수 있다는 것과, 다양한 코드 스타일을 알 수 있다는 것이다.

또한 내가 무의식적으로 사용하던 것들을 설명할 수 있어야 하는데

이 과정에서 내가 알고 있는 것이 진짜 알고 있는 것이 아니라는 것 역시 알게 된다.

 

방어적 복사에 대해 알게 된 것도 이 페어프로그래밍 덕분이다

무의식적으로 getter를 자동완성으로 만들었는데, 페어가 '방어적 복사로 감싸서 보내자!'고 의견을 냈다

 

그리고 난 대답하지 못했다....

 

그래서 방어적 복사는 뭘까?

 

코드와 함께 보자

public class Player {

    private final String name;
    private List<Card> cards;
    
    public Player(String name, List<Card> cards) (
    	this.name = name;
        this.cards = cards;
    }
   
    // 얕은 복사
    public List<Card> getCards() {
        return cards;
    }
    
    // 방어적 복사 1
    public List<Card> getCards() {
        return new ArrayList<>(cards);
    }
    
    // 방어적 복사 2
    public Lit<Card> getCards() {
        return Collections.unmodifiableList(cards);
    }
    
    // 방어적 복사 3
    public List<Card> getCards() {
         return List.copyOf(cards);
    }
}

 

첫번째 방법은 얕은 복사이다.

객체의 주소값을 복사해서 보낸다.

그러므로 복사본에서 내부 값이 바뀐다면, 원본이 바뀔 가능성이 있다.

 

방어적 복사1은 객체의 요소들을 새로운 ArrayList에 담아 보내는 방어적 복사이다.

객체의 참조는 ArrayList에 담겨져서 원본과의 참조가 끊겼지만, List의 요소인 Card는 이전과 같은 곳을 참조한다.

보낸 배열의 수정, 삽입, 삭제가 자유롭다,

 

방어적 복사2는 Collections의 unmodifableList를 이용한 방어적 복사이다

ArrayList를 이용한 방법은 새로운 리스트 참조에 담아 보냈지만, unmodifableList는 원본 주소를 그대로 참조한다

해당 리스트에 수정사항이 일어나면, UnsupportedOperationException을 일으켜 수정을 못하게 막는다

원본을 참조해야할 경우, 이 방법이 적합할 것 같다.

 

이렇게 보면 만능 같지만, 주의할 점도 분명히 존재한다 방어적 복사는 만능이 아니다

 

UnmodifiableList은 만능이 아니다. / 방어적 복사

oracle docs - Collections.unmodifiableList() Returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified li

www.blog.ecsimsw.com

 

방어적 복사3은 List.copyOf()를 이용한다

원본 주소의 참조와, 원본의 수정을 둘 다 막는다.

얕은 복사를 수행해, unModifableLlist로 보낸다.

위 두 방법이 합쳐졌다고 볼 수 있다

 

표로 쉽게 정리하면 다음과 같다

 

  new ArrayList<>(); List.copyOf(); Collection.unModifableList();
복사 후 원본 수정 가능 여부 O X X
원본과의 연결 X X O