
Call by value 와 Call by reference
두 단어의 차이가 뭘까요? 일단 단어의 차이를 비교해보면 각각 value와 reference를 통한 호출이라고 이해할 수 있습니다.
그럼 value는 뭐고, reference는 뭐죠?
그대로 해석해보면 value는 값을 의미하는 것 같고, reference는 참조를 의미하는 것 같습니다.
이 의미를 토대로 해석하면 Call by value는 변수를 지정하면 값(value) 자체를 복사하는 것을 의미합니다.
다음으로 Call by reference는 변수의 주소(참조, reference)를 전달하는 것을 의미합니다.
왜 두 차이를 구분해야 할까요? 근본적으로 모든 값은 메모리에 저장될 테고 call by value도 분명 주소값이 있을텐데 말이에요.
둘을 구분지어야 하는 가장 큰 이유는 다른 함수에 전달될 때 전달되는 방식이 다르기 때문입니다.
#include <stdio.h>
void foo1(int x) {
x = 15;
}
void foo2(int *x) {
x = 15;
}
int main() {
int a = 5;
foo1(a);
printf(a); // 출력값 5
int b = 10;
foo2(&b);
printf(b); // 출력값 15
return 0;
}
C언어를 기준으로 설명하면, foo1() 함수는 call by value이고 foo2() 함수는 call by reference입니다.
먼저 main()함수에서 변수 a에다가 5를 저장하고 foo1(a) 함수에 전달합니다.
foo 함수에는 '복사된 a의 값인 5의 값'이 x에 그대로 전달됩니다.
x라는 새로운 변수가 만들어지는 순간 새로운 주소에 5가 저장되고, 이 값이 15가 갱신됩니다.
따라서 a가 저장된 메모리 주소의 값은 바뀌지 않았으므로 a를 출력하면 5가 나옵니다.
다음으로 변수 b에다가 10을 저장하고, 이번에는 '메모리 주소값'을 전달합니다.
변수 x에는 b의 주소가 전달되고 x를 갱신하면 동시에 b도 갱신이 됩니다.
따라서 b를 출력하면 15로 갱신한 값이 출력됩니다.
자바에서는 Call by value뿐이다
자바에서도 C언어와 비슷하게 두 가지가 모두 있는 것 같지만 Call by reference는 존재하지 않습니다.
함수 안에서 값을 받아 변경하면 함수밖에서도 변경되기 때문에 마치 Call by reference가 있는 것 같습니다.
하지만 자바에서는 원래 할당된 참조는 절대 수정되지 않습니다.
예시코드
public class Main {
public static void main(String[] args) {
MyObject a = new MyObject(5);
MyObject b = new MyObject(10);
System.out.println("호출 전: a = " + a.getValue() + ", b = " + b.getValue());
swap1(a, b);
System.out.println("swap1 후: a = " + a.getValue() + ", b = " + b.getValue());
swap2(a, b);
System.out.println("swap2 후 = " + a.getValue() + ", b = " + b.getValue());
}
public static void swap1(MyObject a2, MyObject b2) {
MyObject c = new MyObject(15);
b2 = c;
}
public static void swap2(MyObject a3, MyObject b3) {
int temp = a3.getValue();
a3.setValue(b3.getValue());
b3.setValue(temp);
}
}
결과
코드로 볼까요?
swap이라는 함수는 흔히들 아는 두 값 바꿔치기 함수입니다. a와 b의 값을 바꾸는 것이죠.
MyObject 클래스는 편의상 삭제했습니다. 내부에 value가 있고 getter 와 setter가 있다고 가정합니다.
1. swap1 - 새로운 객체가 할당되었을 때
swap1 함수가 실행되었을 때 a2와 b2에 값(value)이 전달될 수도 있고, 주소(reference)가 전달될 수도 있습니다.
C언어 처럼 주소값을 표기하는 것은 없기 때문에 둘 다 된다고 일단 가정해봅시다.
public static void swap1(MyObject a2, MyObject b2) {
MyObject c = new MyObject(15);
b2 = c;
}
swap 메소드에서 새로운 객체 c를 만들었고, 값은 15로 정했습니다.
그리고 b2 에다가 c를 할당하고 있습니다. c에는 MyObject 객체의 주소값이 담겨있을 겁니다.
따라서 b2에는 c의 주소가 들어있습니다.
1) 만약 value를 복사한다면
b2에 새로운 주소에 b2객체가 생성되었을 것이고, 이 값에 c 주소가 들어있을 겁니다.
따라서 swap1 함수를 빠져나가는 순간 기존 b 객체의 주소값은 건드린적이 없으므로 변화가 없을 겁니다.
2) 만약 reference를 복사한다면
b2에 b의 주소를 복사했을 것이고, 여기에 c 주소를 대입했을 겁니다.
따라서 swap1 함수를 빠져나가면 b의 값은 15를 가진 새로운 MyObject가 되어있을 겁니다.
결과를 보면 b의 값은 바뀌지 않았습니다. 즉, value를 복사하는 것이 되겠죠.
b2는 가비지컬렉터에 의해 냠냠을 당하게 됩니다.
2. swap2 - 객체를 통한 접근을 시도할 때
public static void swap2(MyObject a3, MyObject b3) {
int temp = a3.getValue();
a3.setValue(b3.getValue());
b3.setValue(temp);
}
이 코드의 차이가 뭘까요? 똑같이 a3, b3 객체를 만들어서 이번에는 직접 객체에 접근해 메소드로 수정하고 있네요.
a3의 값을 가져와서 temp에 저장하고, a3의 값을 b3의 값으로 바꾸고, b3의 값을 temp로 바꿨습니다.
결과를 볼까요? 실제로 b의 값도 변경되었습니다.
어? 이러면 call by reference랑 똑같은거 아냐? 아까 java에는 없다며....
아쉽게도 거짓말을 하진 않았습니다. 자바에서는 call by value 뿐입니다.
이를 위해서는 stack과 heap에 대해서 조금 이해가 필요합니다.
자바에서 변수들은 stack에 쌓이고, heap영역의 객체를 가리키는 메모리 주소값이 저장됩니다.
실제 객체 데이터는 heap영역에 있게 됩니다. main()함수가 실행되고, swap2()함수가 실행됐을때의 모습입니다.
a3, b3가 변수가 생성될때 정확히 주소값(value)이 복사가 됩니다.
그래서 이 주소값으로 heap영역의 객체에 접근하여 값을 수정할 수 있게 됩니다.
.....그럼 call by reference랑 뭐가 다른데?
public static void swap1(MyObject a2, MyObject b2) {
b2 = new MyObject(15);
}
아까 swap1을 다시 가져와서 응용(?)한 코드로 보면 정확해집니다.
만약 전달 방식이 call by reference라면, 새로 생성된 객체의 주소값이 b에도 전달될 것이며 값이 15로 바뀌어야 합니다.
또한 b의 주소가 이 새로운 객체 주소로 바뀌어야 하죠.
하지만 b에는 영향을 주지 못합니다.
swap1 안에서 호출한 b의 메모리 주소값을 변경하는데 영향을 주지 못하기 때문에 call by reference라고 할 수 없습니다.
값을 바꿀수 있어서 동작 자체는 비슷해 보일 수 있겠지만요.
결론
자바에서 모든 값 전달은 Call by value입니다.
참고자료
자바는 Call By Value일까? Call By Reference일까?
결론부터 말하자면 Call By Value 다. Call By Reference처럼 동작하는 것 같기도한데? 하며 헷갈릴 수 있는 부분을 정확히 그림을 통해 어떤 차이점이 있는지 비교 해보고자 한다. Call By Value란 메소드의
velog.io
[Java] Java는 Call by reference가 없다
Call by Value와 Call By Reference가 뭘까? 프로그래밍을 하다 보면 꼭 알고 넘어가야 하는 개념이 있습니다. 바로 Call By Value, Reference입니다. 어떤 언어를 공부하든 나오는 개념이기도 합니다. Call by value
deveric.tistory.com
'Language > JAVA' 카테고리의 다른 글
String 클래스 파고들기 - 객체의 특성 및 더하기 연산의 버전별 차이 (0) | 2024.04.09 |
---|---|
String 클래스 파고들기 - String 생성과 byte 변환시 주의점 (0) | 2024.04.05 |
자바가 돌아가는 동작 원리 (0) | 2024.03.06 |
기본형 타입과 참조형 타입 (0) | 2023.02.21 |
추상 클래스 정리 (0) | 2022.10.24 |
남에게 설명할 때 비로소 자신의 지식이 된다.
포스팅이 도움되셨다면 하트❤️ 또는 구독👍🏻 부탁드립니다!! 잘못된 정보가 있다면 댓글로 알려주세요.