차곡차곡 성 쌓기

코테를 풀다가 재귀 호출할 때 값이 갱신되지 않았다.

문제의 코드는 아래인데, 최종 갱신되는 result 값을 함수의 반환값으로 넘기고 싶었다. 근데 값이 분명 10으로 바뀌었는데 이전 콜스택으로 넘어가니 다시 기존 값이 되었다.

<code />
private void nCr(int depth, int N, int R, boolean[] v, int result, int [][] friends){ if(depth == R){ // 계산 // 이때 갱신이 안되나? 안됨. 왜 안돼? result = Math.min(result, diff(v, friends)); // min 값 갱신 return; } for(int i = depth; i<N; i++){ v[i] = true; nCr(depth+1, N, R, v, result, friends); v[i] = false; } }

 

우선 래퍼런스 객체가 아니여서 그런가? 했다.

int와 long 처럼 자바의 기존 타입은 값에 의한 호출(pass by value)로 값만 복사되어 넘어간다고 한다. 그래서 값이 변경될 수가 없다.

 

그래서 래퍼런스 타입으로 알고있는 Integer 객체를 사용했다. 하지만 마찬가지로 값이 갱신이 안됐다. 이유를 찾아보니 Integer, String 와 같은 래퍼 클래스는 불변객체라고 한다. 불변객체란 한 번 생성된 값이 변하지 않는다는 특성을 가진다. 그럼 아예 변하지 않는 것일까? 

 

확인해보니,  아래 대입 연산을 할 때 새로운 Integer 객체가 생성된다.

<code />
result = Math.min(result, diff(v, friends));

 

래퍼런스 변수 답게 하나의 객체를 계속 사용할 줄 알았는데, 매번 새롭게 생성되서 혼동이 왔다.

 

그 이유는 Integer는 참조 타입(Reference Type)이긴 하지만, 불변 객체이기 때문이다. 즉 값이 변경되어도 내부적으로 새로운 Integer 객체가 생성될 뿐, 원래 객체가 변경되지 않는다.

 

또한 대입 연산자(=)는 참조(주소)를 변경하는 역할을 한다. 기존 result에 새로운 객체를 넣는 것이 아니라, 새로운 객체를 가리키도록 하는 것이다. 때문에 이때 result는 새로운 Integer 객체를 가리키게 되어서 기존의 객체와 연결이 끊어지게 된다. 그러니 갱신이 될리가 없다.

 

그러면 갱신을 해줄려면?

가변객체이면서 레퍼런스 변수를 이용하면 된다. 흔히 알고있는 배열([])을 사용하면 되는 것이다. 왜냐? 배열은 래퍼런스(주소 가리킴) 변수면서 내부의 값을 변경할 수 있는 가변 객체이기 떄문이다.

<code />
private void nCr(int depth, int N, int R, boolean[] v, int [] result, int [][] friends){ if(depth == R){ // 계산 result[0] = Math.min(result[0], diff(v, friends)); // min 값 갱신 return; } for(int i = depth; i<N; i++){ v[i] = true; nCr(depth+1, N, R, v, result, friends); v[i] = false; } }

 

이러면 이전 콜스택으로 되돌아 와도 갱신된 값이 저장된다!

 

 

profile

차곡차곡 성 쌓기

@nagrang

포스팅이 좋았다면 좋아요