값에 의한 호출
함수가 호출될 때, 메모리 공간 안에서는 함수를 위한 별도의 임시공간이 생성됨
➡️ 종료 시 해당 공간 사라짐
함수 호출 시 전달되는 변수 값을 복사해서 함수 인자로 전달
➡️ 이때 복사된 인자는 함수 안에서 지역적으로 사용되기 때문에 local value의 속성 가짐
void func(int n) {
n = 20;
}
void main() {
int n = 10;
func(n);
printf("%d", n);
}
참조에 의한 호출
void func(int *n) {
*n = 20;
}
void main() {
int n = 10;
func(&n);
printf("%d", n);
}
항상 call by value로 값을 넘김
C/C++와 같이 변수의 주소값 자체를 가져올 방법이 없으며 이를 넘길 수 있는 방법 또한 없음
참조 자료형(reference type)을 넘길 때는 해당 객체의 주소값을 복사하여 사용
User a = new User("gyoogle"); // 1
foo(a);
public void foo(User b){ // 2
b = new User("jongnan"); // 3
}
/*
==========================================
// 1 : a에 User 객체 생성 및 할당(새로 생성된 객체의 주소값을 가지고 있음)
a -----> User Object [name = "gyoogle"]
==========================================
// 2 : b라는 파라미터에 a가 가진 주소값을 복사하여 가짐
a -----> User Object [name = "gyoogle"]
↑
b -----------
==========================================
// 3 : 새로운 객체를 생성하고 새로 생성된 주소값을 b가 가지며 a는 그대로 원본 객체를 가리킴
a -----> User Object [name = "gyoogle"]
b -----> User Object [name = "jongnan"]
*/
파라미터 객체/값의 주소값을 복사하여 넘겨주는 방식을 사용하고 있는 Java는 주소값을 넘겨 주소값에 저장되어 있는 값을 사용하는 call by reference라고 오해할 수 있음
// c/c++
int a = 10;
int b = a;
cout << &a << ", " << &b << endl; // out: 0x7ffeefbff49c, 0x7ffeefbff498
a = 11;
cout << &a << endl; // out: 0x7ffeefbff49c
C/C++에서는 생성한 변수마다 새로운 메모리 공간을 할당하고 이에 값을 덮어씌우는 형식으로 값을 할당
(* 포인터를 사용한다면 같은 주소값을 가리킬 수 있도록 함)
//java
int a = 10;
int b = a;
System.out.println(System.identityHashCode(a)); // out: 1627674070
System.out.println(System.identityHashCode(b)); // out: 1627674070
a = 11;
System.out.println(System.identityHashCode(a)); // out: 1360875712
Java에서 또한 생성한 변수마다 새로운 메모리 공간을 갖는 것은 마찬가지이지만 그 메모리 공간에 값 자체를 저장하는 것이 아니라 값을 다른 메모리 공간에 할당하고 이 주소값을 저장하는 것
➡️ C/C++에서는 주소값 자체를 인자로 넘겼을 떄 값을 변경하면 새로운 값으로 덮어 쓰여 기존 값이 변경되고, Java에서는 주소값이 덮어 쓰여지므로 원본 값은 전혀 영향이 가지 않음
Call by value의 경우 데이터 값을 복사해서 함수로 전달하기 때문에 원본의 데이터가 변경될 가능성이 없다. 하지만 인자를 넘겨줄 때마다 메모리 공간을 할당해야해서 메모리 공간을 더 차지한다.
Call by reference의 경우, 메모리 공간 할당 문제는 해결했지만 원본 값이 변경될 수 있다는 위험이 존재한다.
[참고 자료]