오늘은 스터디를 진행하면서 커뮤니티에서 본 자바의 Call By Reference에 대해 정리하려고 한다.
먼저 기본적인 Call by value와 Call by reference에 대해 짚고 넘어가자.
Call by value
함수를 호출 할 때 단순히 값을 전달하는 형태의 함수 호출을 의미한다.
Call by reference
메모리의 접근에 사용되는 주소 값을 전달하는 함수 호출을 의미한다.
자바는 Call By Reference가 없다?
Java에서 primitive type 변수는 실제 값을 저장하는 반면 다른 모든 타입 변수는 참조하는 객체의 주소를 가리키는 참조 변수를 저장한다.
객체의 주소를 가리키는 참조 변수가 스택 메모리에 저장된다. 참조하는 객체는 힙 메모리에 저장된다.
총 2번의 과정을 거치는 것이다.
자바는 단순한 Call By Reference가 아니다.
객체가 인수로 전달될 때 원래 참조 변수의 동일한 객체 주소를 가리키는 참조 변수의 정확한 복사본이 생성되기 때문이다.
public class CallByValue {
@Test
public void whenModifyingObjects_thenOriginalObjectChanged() {
Foo a = new Foo(1);
Foo b = new Foo(1);
// Before Modification
assertEquals(a.num, 1);
assertEquals(b.num, 1);
modify(a, b);
// After Modification
assertEquals(a.num, 2);
assertEquals(b.num, 1);
System.out.println("======");
System.out.println(b.toString()); //Foo@3337d04c
System.out.println(b.num);
}
public static void modify(Foo a1, Foo b1) {
a1.num++;
b1 = new Foo(1);
b1.num++;
System.out.println(b1.toString()); //Foo@2f521c4
System.out.println(b1.num);
}
static class Foo {
public int num;
public Foo(int num) {
this.num = num;
}
}
}
테스트는 전부 통과하며 아래는 출력 문이다.
Call By Reference라면 메서드에서 동일한 객체를 변경할 때마다 해당 변경 사항이 원래 객체에 반영되야 한다.
그러나 전달된 참조 변수에 새 개체를 할당하면 원래 객체에 반영되지 않는다. 변수 b의 경우가 지금 그렇다.
이는 스택에 저장되어 있는 참조 변수의 복사본이 함수 인수로 넘어갔기 때문이다.
따라서 void whenModifyingObjects_thenOriginalObjectChanged 메서드의 지역변수인 b가 변경되지 않았다.
정리
- 자바는 call by value만 존재한다.
- 자바의 reference는 reference value의 줄임말이다.
- 자바에서는 reference 값을 call by value로 전달하면 호출된 매서드 내에서 호출 한 쪽에서 참조하고 있던 오브젝트 내부 값을 변경할 수 있다.
참고 자료
https://www.baeldung.com/java-pass-by-value-or-pass-by-reference
https://m.facebook.com/story.php?story_fbid=pfbid02ct5qtQ26ceeBcnxMw5fBHh7XMuXeiCZ1BvGA2pKekkfXvecTHWwtU5dHUS6G87vBl&id=1070166746&mibextid=9R9pXO
https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value
댓글