본문 바로가기
Club/99클럽 코테 스터디 2기

99클럽 코테 스터디 14일차 TIL Java List 복사와 참조

by ʚ⇜❅🎕̈❄⇝ɞ 2024. 6. 2.
728x90
반응형

Java List 복사와 참조의 차이

주어진 graph에서 start node에서 end node로 갈 수 있는 모든 path를 구하는 코딩테스트 문제를 푸는 와중에 논리 오류(Logical Error)를 맞닥뜨렸다.

List 복사 시 발생한 오류인데, 그에 관한 내용을 정리해 본다.

 

  • 논리 오류가 발생한 코드
    • start node 0에서 end node 4로 가기 위한 path를 구해보겠습니다.
    • 첫 번째 path인  [0, 1, 4]를 구하여 answer.add(path); 해주었습니다.
    • 두 번째 path인  [0, 3, 4]를 구하여 answer.add(path); 해주었습니다.
    • answer을 출력해 보았습니다. 
    • 기대한 값은 [[0, 1, 4], [0, 3, 4]]이었으나,,,
    • 실제로는 [[0, 3, 4], [0, 3, 4]]가 출력되었습니다.
    • 어디가 문제일까요??
List<List<Integer>> answer = new ArrayList<>();
List<Integer> path = new ArrayList<>();

// path #1
path.add(0);
path.add(1);
path.add(4);

answer.add(path);

// path = [0, 1, 4]
System.out.println("path = " + path);
// answer = [[0, 1, 4]]
System.out.println("answer = " + answer);

// path #2
path.remove(2);
path.remove(1);

path.add(3);
path.add(4);

answer.add(path);

// path = [0, 3, 4]
System.out.println("path = " + path);
// 논리 오류 발생!!
// 기대 출력 값 : answer = [[0, 1, 4], [0, 3, 4]]
// 실제 출력 값 : answer = [[0, 3, 4], [0, 3, 4]]
System.out.println("answer = " + answer);

 

  • 논리 오류를 해결한 코드
    • answer.add(path) 대신 answer.add(new ArrayList<>(path)) 를 사용한다.
    • 실제 answer 값이  [[0, 1, 4], [0, 3, 4]] 가 출력되는 것을 볼 수 있다!
List<List<Integer>> answer = new ArrayList<>();
List<Integer> path = new ArrayList<>();

// path #1
path.add(0);
path.add(1);
path.add(4);

answer.add(new ArrayList<>(path));

// path = [0, 1, 4]
System.out.println("path = " + path);
// answer = [[0, 1, 4]]
System.out.println("answer = " + answer);

// path #2
path.remove(2);
path.remove(1);

path.add(3);
path.add(4);

answer.add(new ArrayList<>(path));

// path = [0, 3, 4]
System.out.println("path = " + path);
// 의도한 Logic!!
// 기대 출력 값 : answer = [[0, 1, 4], [0, 3, 4]]
// 실제 출력 값 : answer = [[0, 1, 4], [0, 3, 4]]
System.out.println("answer = " + answer);

 

  • List의 주소를 참조하는 answer.add(path)
    • List의 주소를 참조한 path 객체를 추가하므로 answer에 add 한 모든 path는 같은 path 객체를 가리킨다.
    • 모든 경로를 탐색할 동안 path는 계속 수정되기 때문에, answer에 추가한 모든 path는 최종적으로 같은 값을 가지게 된다.
  • List의 값을 복사하는 answer.add(new ArrayList<>(path))
    • List에 path의 현재 값을 복사하여 새로운 path 리스트 객체를 만든다.
    • 다른 경로를 탐색할 동안 path가 수정되더라도 answer에 추가된 path는 영향을 받지 않는다.
    • 즉, 각 path 객체는 독립적인 상태를 유지한다.
  • 결론
    • 위 두 방법 중 틀린 방법은 없다.
    • answer.add(path)가 틀린 방법이 아니라 의도하지 않은 방법(Logical Error)이란 것이다.
    • 중요한 것은 작성한 코드가 본인이 의도한 대로 동작하는가이다.
728x90

알게 된 점

  • 주소 참조와 값 복사는 이론으로 배우긴 했으나, 실제로 처음 맞닥뜨린 사례이다.
  • 앞으로 이론을 배우면 실습 코드를 무조건 작성해 봐야겠다.

다음에 학습할 것

  • List 이외의 다른 객체들에서의 주소 참조와 값 복사에 대하여
반응형

Java 코딩 테스트에서 알고리즘은 잘 구현해 놓고 이런 실수가 있지 않도록 주의해야겠다.

728x90
반응형

댓글