코테를 풀다가 재귀 호출할 때 값이 갱신되지 않았다.
문제의 코드는 아래인데, 최종 갱신되는 `result` 값을 함수의 반환값으로 넘기고 싶었다. 근데 값이 분명 10으로 바뀌었는데 이전 콜스택으로 넘어가니 다시 기존 값이 되었다.
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 객체가 생성된다.
result = Math.min(result, diff(v, friends));
래퍼런스 변수 답게 하나의 객체를 계속 사용할 줄 알았는데, 매번 새롭게 생성되서 혼동이 왔다.
그 이유는 `Integer`는 참조 타입(Reference Type)이긴 하지만, 불변 객체이기 때문이다. 즉 값이 변경되어도 내부적으로 새로운 Integer 객체가 생성될 뿐, 원래 객체가 변경되지 않는다.
또한 대입 연산자(`=`)는 참조(주소)를 변경하는 역할을 한다. 기존 result에 새로운 객체를 넣는 것이 아니라, 새로운 객체를 가리키도록 하는 것이다. 때문에 이때 `result`는 새로운 Integer 객체를 가리키게 되어서 기존의 객체와 연결이 끊어지게 된다. 그러니 갱신이 될리가 없다.
그러면 갱신을 해줄려면?
가변객체이면서 레퍼런스 변수를 이용하면 된다. 흔히 알고있는 배열(`[]`)을 사용하면 되는 것이다. 왜냐? 배열은 래퍼런스(주소 가리킴) 변수면서 내부의 값을 변경할 수 있는 가변 객체이기 떄문이다.
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;
}
}
이러면 이전 콜스택으로 되돌아 와도 갱신된 값이 저장된다!