단순한 코드로 오늘의 문제를 확인해보겠다.
참고로 이 문제를 해결할 때 까지 소요된 시간은 총 3시간 정도 된다.
public class RodcPapperScissor {
public static String[] rps = {"R", "P", "S"};
public static void main(String[] args) {
ArrayList<String[]> ls = rockPaperScissors(3);
for (int i = 0; i < ls.size(); i++) {
System.out.println(i + "번째 인자 : " + Arrays.toString(ls.get(i)));
}
}
public static ArrayList<String[]> rockPaperScissors(int rounds) {
// TODO:
ArrayList<String[]> ls = new ArrayList<>();
String[] tmp = new String[]{}; //배열을 만든다 어차피 재귀하면서 돌릴꺼임 이거 귀찮으면 리스트로 만들어서 마지막에 변환하는 방법도 있음
return choiceString(ls, tmp, rounds);
}
public static ArrayList<String[]> choiceString(ArrayList<String[]> ls, String[] tmp, int rounds) {
//종료 시점 종료할 때만 ls에 add를 해서 값을 넣어라
if (rounds == 0) {
ls.add(tmp);
return ls;
}
String[] temp = Arrays.copyOf(tmp, tmp.length + 1);
//note 배열의 크기를 1 증가 시킨다.
for (int i = 0; i < rps.length; i++) {
temp[temp.length - 1] = rps[i]; //todo 배열의 마지막 인덱스에 rps의 i번지 값을 저장한다.
ls = choiceString(ls, temp, rounds - 1);
}
return ls;
}
}
//note 이거 틀리는 이유 얕은 결합 상태라 그런가?
단순하게 위의 코드를 한번확인해보겠다.
위의 코드는 입력받은 숫자 만큼 제공되는 배열에서 뽑아 출력하는 코드다.
자 rounds가 2라고 해보자
그렇다면
tmp = [R] 일 떄 rounds = 1; 이 된다.
tmp 의 길이를 하나 늘려 temp 라는 배열을 만들어 준다.
그렇다면 temp = ["R", null] 이 된다.
for문을 돌려보자
i가 0 일때는 ["R", "R"]
rounds를 1 줄여 rounds = 0 이 되고
여기서 재귀를 호출하게된다.
그렇다면 위의 탈출 조건에 따라 ls 에 위의 배열을 저장하고
i 의 값을 증가시킨다.
i가 1 일때는 ["R", "P"]
rounds를 1 줄여 rounds = 0 이 되고
여기서 재귀를 호출하게된다.
그렇다면 위의 탈출 조건에 따라 ls 에 위의 배열을 저장하고
i 의 값을 증가시킨다.
i가 2 일때는 ["R", "S"]
rounds를 1 줄여 rounds = 0 이 되고
여기서 재귀를 호출하게된다.
그렇다면 위의 탈출 조건에 따라 ls 에 위의 배열을 저장하고
i 의 값을 증가시킨다.
그렇게 되면 for 문을 만족 시키지 않기 때문에 바로 return 으로 들어가게된다.
그렇다면 리스트에는 ["R", "R"] , ["R", "P"], ["R", "S"] 가 들어가 있을까??
NO!! 절대 아니다.
이유는 무엇인가?
일단 배열을 선언할 때의 변수가 어떤 변수인가???
배열을 선언하는 변수는 참조 변수이다.
즉 배열을 저장하고 있는 것이 아니라 배열의 주소값을 저장하고 있게 된다.
그렇다면 배열을 저장하고 있는 리스트에 있는 요소들은 무엇인가?
배열의 값들이 직접 저장되는가??
NO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
배열의 주소값들이 저장되게 된다.
이 때 위의 로직을 확인해보자
i값이 변경하던말던 리스트에 저장되는 값이 무엇인가?
배열temp의 주소값이 저장이된다.
그렇기에 list index 0~2 까지 모두 같은 배열의 주소값을 요소로 가지고 있다.
말로 설명하니 나도 잘 설명하고 있는지 모르겠다.
그렇다면 결과를 보여주겠다.

보면 뒤에 주소값이 모두 일치한다>>>>>>>>>>>>>>>>>>>>>>>>>>>>그렇기 때문에 for문을 마지막 수행했을 때의 결과가 저장이 된다.
이건 왜그런가?
이 것의 핵심 문제는 배열의 인스턴스를 저장하는 변수는 배열을 저장하는 것이 아니라 배열 인스턴스의 참조값을 가지고 있다.라는 것이다.
사실 이 문제를 해결하고 나서 가장 먼저 생각한 것이 깊은 복사 얕은 복사다.
얕은 복사
정확하게 위의 내용과 관계가 있다고 할 수는 없지만 얕은 복사 깊은 복사의 개념을 알면 쉽게 이해할 수 있다.
얕은 복사의 경우는 인스턴스를 복사하는 것이 아니라 인스턴스를 가리키는 참조값을 복사해서 할당 해주는 방식이다.
인스턴스를 복사하는 것이 아니기 때문에 해당 인스턴스를 변경한다면 복사한 변수에서 가리치는 인스턴스에서도 값이 변경이된다.
깊은 복사
이건 새로운 인스턴스를 하나 만들어서 할당해주는 것이다.
이렇게 하면 초기에 복사한 인스턴스의 내용물은 같겠지만 서로 독립되 인스턴스가 되어 복사했던 인스턴스의 값이 변경된다고 하더라도 복사된 인스턴스에서의 값이 변경되지 않는다.
전혀 상관이 없는 내용이지만 참조값을 저장한다는 것에서 의식의 흐름이 여기까지 갔던것 같다.
글을 쓰며 와 전혀 관계가 없는데? 라는 생각도 했지만
그래도 얕은복사 깊은 복사에 대해 설명하고 싶어서 관계가 없지만 넣어봤다.
'이전 학습 내용' 카테고리의 다른 글
| 오늘의 띠용@!@(네스트 클래스 테스트) (0) | 2022.12.02 |
|---|---|
| NPE (0) | 2022.11.29 |
| 오늘의 배움 코드를 쓰는 줄이 중요하다. (0) | 2022.11.25 |
| 오늘의소소한 고민 getName이 오류가 뜬 이유는? (0) | 2022.11.23 |
| Thread 임계 구역 설정의 중요성( 동기화) (0) | 2022.11.23 |