CS

자바는 Call by Value

frog-in-well 2022. 12. 28. 15:13

자바는 Call by Value를 사용한다. 자바 코드와 함께 정리가 잘 된 글들이 많지만 아주 간단하고 쉽게 정리해보겠다.

1. Call by Value vs. Call by Reference

함수가 호출될 때, 메모리 공간에서는 임시의 공간이 생성된다. 함수가 종료되면 공간이 사라진다. (더 자세한 내용은 Garbage Collector를 공부해보면 된다.)

1. Call by Value

  • 함수 호출 시 전달 되는 변수의 값을 복사하여 함수의 인자로 사용한다.
  • 복사된 인자는 함수 내부에서 지역 변수로 사용된다.

2. Call by Reference

  • 함수 호출 시 인자로 전달 되는 변수의 참조를 전달한다.
  • 함수 내부에서 인자의 값이 변경되면, 참조된 변수들도 값이 바뀐다.

 

JVM에서는 원시 타입은 Stack 영역에 변수와 함께 저장되며, 참조 타입은 객체는 Heap 영역에, 객체의 주소값은 변수와 함께 Stack 영역에 저장된다.

이 때, 함수가 호출되면, 동일한 객체를 가르키고 있지만 Call by Value 이기 때문에 새로운 Reference를 만들어서 전달한다. 

그런데, Java에서 참조 타입 변수들을 사용하다보면, Call by Reference라고 느껴지는 경우가 있다.

2. Java에서 Call by Value

main 메소드에서 변수를 선언하고, modify 메소드에서 해당 변수의 값을 바꾸는 코드가 있다고 해보자. 

2.1 원시 타입

원시 타입 변수를 modify 메소드의 인자로 넘겨주면, Call by Value이기 때문에 Stack에 동일한 값이 복사된다.

modify 메소드 내부에서 a의 값을 20으로 바꾸면, 메소드 내부에서만 값이 바뀐다.

 

2.2 참조 타입

StringObject라는 객체가 있고 value라는 속성을 가진다고 하자. 

객체 선언, modify 메소드 실행, 객체 변경 순서대로 살펴보자.

 

1. 객체 선언

main 메소드에서 객체를 생성하면 Stack 영역에는 변수와 해당 객체의 참조(주소값)이 생성되며, Heap 영역에는 객체가 생성된다.

 

2. modify 메소드 실행

modify() 메소드를 실행하면 Java는 Call by Value 이기 때문에, 동일한 객체를 가르키는 참조를 복사하여 Stack에 생성한다. 

이제, 객체의 값을 변경해보자. 

 

3. 객체 변경

a에는 기존 객체의 참조가 저장되어 있었는데, new 연산자를 통해 새로운 객체를 생성하면 modify 메소드 내부의 a는 새로운 객체를 가르킨다. 결국, 메소드에서 반환되었을 때, main 메소드에서 가르키고 있던 a는 기존의 객체를 가르키고 있다.

  • main() 메소드 실행 시 a 값은 "10"
  • modify() 메소드 내부에서 a 값은 "20"
  • modify() 메소드 종료 후, main() 메소드에서 a 값 출력 시 "10"

그럼 Java에서는 메소드 내부에서 외부의 값을 변경하지 못하는 것인가? 당연히 아니다.

아래와 같이 메소드에서 참조하고 있는 객체의 속성에 접근하면 된다.

객체의 속성에 접근하여 값을 변경하면, modify 메소드 내부에서 새로운 참조가 생성되지 않고 마치 Call by Reference와 같이 사용되는 효과를 얻게 된다.