자바는 Call By Value 방식으로 동작한다.
Call By Value와 Call By Reference는 메서드 호출 시 파라미터를 전달하는 방식이다.
Call By Value는 값을 그대로 복사해서 넘겨주는 것이고,
Call By Reference는 참조(주소)를 넘겨주는 것이다. 따라서 메서드 내 파라미터를 수정하면 원본 변수도 변하게 된다.
자바에서는 어떤 방식을 사용할까?
자바에는 두가지 데이터 타입이 있다.
자바에서 변수를 선언하면 스택 메모리 영역에 할당된다.
스택 내부에 메소드마다 영역이 각각 나뉘어 있고, 서로 다른 변수로 존재한다.
따라서 파라미터에 값을 변경해도 원본에는 영향을 주지 않는다.
즉, Primitive 타입의 전달은 값을 복사해 전달하는 Call By Value이다.
Reference 타입의 객체는 Heap 영역에 저장되고, 스택에 있는 변수가 객체의 주소를 갖고 있다.
메소드의 변수로 객체를 넘길때는 참조값(주소)의 복사본이 넘어간다.
메소드 내에서 객체의 내부를 바꾸면 반영되지만, 객체를 새로 할당하거나, 다를 객체 가르켜도 원본 객체에는 영향이 없다.
Call By Reference라면 새 객체가 할당되어야 한다.
class Person {
int age;
String name;
}
public void method1() {
Person person = new Person(25, "Nick");
System.out.println(person.age + person.name); // 25, Nick
method2(person);
System.out.println(person.age + person.name); // 30, Nick
}
public void method2(Person person) {
person.age = 30; // person 객체 내부 수정됨.
person = new Person(22, "Ahn"); // 새로운 객체 가리킴.
System.out.println(person.age + person.name); // 22, Ahn
}

참조값(주소)가 변경되었기 때문에, 원본값에는 영향을 주지 않는다.

Call By Reference를 사용하는 C++의 경우, 포인터를 사용해서 주소값을 복사한다.
해당 주소의 값에 직접적으로 접근하여 값을 변경한다.
// Java
class Box {
int value;
}
void change(Box b) {
b.value = 100; // 원본 객체 필드 수정
b = new Box(); // 새로운 객체 할당: 외부 영향 없음
b.value = 200;
}
public static void main(String[] args) {
Box box = new Box();
box.value = 10;
change(box);
System.out.println(box.value); // 결과: 100
}
// C++
class Box {
public:
int value;
};
void change(Box& b) {
b.value = 100; // 원본 객체 필드 수정
b = Box(); // 원본 객체 자체를 새 객체로 대체
b.value = 200;
}
int main() {
Box box;
box.value = 10;
change(box);
cout << box.value; // 200
}
Box& b는 box 자체에 대한 참조(alias)이므로, b = Box();는 원본 box 자체를 새로운 객체로 대체한 것이다.
결론적으로 자바는 객체 전달 시 참조값을 복사한 것이고, 객체 내부는 변경 가능하지만, 객체 자체는 바꿀 수 없다.
C++은 실제 변수 자체의 alias를 전달한것이기에 직접적으로 연결되어 있고, 객체 자체의 교체가 가능하다.
JavaScript 또한 참조 타입은 참조값 복사를 통해 자바와 비슷한 방식으로 Call By Value만을 사용한다.
<참고>