본문 바로가기

항해 99/Spring

Call by Reference

자바의 Call by Value / Call by Reference

함수의 매개변수에서 값을 복사하느냐 주소값을 참조하느냐에 따라 반환 결과가 달라지기 때문에 대부분의 프로그래밍 교육 과정에서는 중요시 하게 여김

 

자바의 데이터 타입은 크게 두 가지로 나뉨

  • 기본형(primitive type) : Boolean Type(boolean), Numerice Type(short, int, long, float, double, char)
  • 참조형 (reference type) : Class Type, Interface Type, Array Type, Enum Type, 기본형을 제외한 모든 타입

메서드에 입력값(파라미터)에 원시값(primitive type)을 전달하는 것과 객체(reference type)를 전달하는 것에는 큰 동작 차이가 있음

 

Call by Value / Reference

1.  main  스택 프레임에 두 변수가 담김

primitive 타입인 변수 var은 그대로 원시값 1을 지니게 되며, reference 타입인 변수 arr의 실제 데이터는 heap 영역에 저장되게 되고 이를 참조할 주소값을 저장하게 됨

[스택 프레임(stack frame)]
하나의 메서드에 필요한 메모리 덩어리를 묶어서 스택 프레임(Stack Frame)이라고 한다.
하나의 메서드당 하나의 스택 프레임이 필요하며, 메서드를 호출하기 직전 스택프레임을 자바 Stack에 생성한 후 메서드를 호출하게 된다.
스택 프레임에 쌓이는 데이터는 메서드의 매개변수, 지역변수, 리턴값 등이 있다.
만일 메서드 호출 범위가 종료되면 스택에서 제거된다.

 

2. add_value() 메서드에 입력값으로 변수 var을 넣어 호출한다

add_value() 메서드가 호출되면서, add_value 스택 프레임이 생성되고 그 안에 지역변수(매개변수) var_arg가 값을 1을 받은 채 생성되게 된다.

그리고 자체 메서드 로직으로 100을 더해 값은 101이 된다.

 

3. var 변수값은 변하지 않는다

add_value 스택 프레임 안에 있는 변수 var_arg가 바뀐 것이지, main 스택 프레임 안에 있는 변수 var 가 바뀐 것이 아니다.

매개변수 var_args는 그저 변수 var로부터 원시값을 복사하여 받은 것 뿐이기 때문이다. (call by value)

즉,  메인에 정의되어 있는 var 변수와 add_value 메서드에 정의되어 있는 var_arg 변수는 서로 완전히 남남이다.

 

4. add_reference() 메서드에 입력값으로 변수 arr를 넣어 호출한다

add_reference() 메서드가 호출되면서, add_reference 스택 프레임이 생성되고 그 안에 지역변수(매개변수) arr_arg가 생성된다.
이때도 전의 add_value() 메서드 호출 때 처럼 변수의 값이 복사되어 파라미터에 넘겨지는데, 자세히 살펴보니 스택 프레임에 있는 arr 변수가 들고 있는 값은 주소값 이다.

그래서 메서드의 입력값으로 주소값이 복사되어 넘겨지게 된다.

따라서 결과적으로 두 변수 arr 와 arr_arg는 같은 주소값을 들고 있게 되는 것이고, 이 주소가 가리키는 메모리는 같기 때문에 두 변수는 하나의 데이터를 동시에 참조하고 있다고 말 할 수 있다.

마지막으로 arr_arg 변수가 가리키는 값 1을 불러와 100을 더하니 heap 영역에 있는 데이터는 101로 변경되게 된다.

참조값(주소값) 복사는 배열 뿐만 아니라 클래스, 리스트, 맵 등 primitive 타입이 아닌 모든 타입에 대해서 적용된다.

 

5. 마지막으로 변수 arr를 출력해보면 값이 변경됨을 알 수 있다

 

자바에는 Call by Reference 개념이 없음

자바(Java) 프로그래밍 언어에서는 call by reference라는 것은 존재하지 않는다, C언어와는 다르게 자바에서는 포인터를 철저하게 숨겨 개발자가 직접 메모리 주소에 접근하지 못하게 조치했기 때문이다

C언어는 포인터를 통해 그대로 주소를 통해 메모리를 참조할 수 있다

 

자바에서의 파라미터는 call by value로서만 동작되며, 원시값이 복사 되느냐 주소값이 복사되느냐 차이가 있을 뿐임

매개변수에 복사된 값에 따라, 원시값이면 바로 연산하고 주소값이면 해당 메모리 주소를 참조해 값을 가져와 연산한다

 

C언어의 Call by Reference

C언어에서는 포인터(*) 변수를 파라미터 받게 하고함수를 호출할 때 주소연잔사(&)를 이용해 주소값을 직접 넘겨 직접적인 메모리 참조가 가능하다

#include <stido.h>

void swap(int *, int *);

int main() {
      int a = 10;
      int b = 20;
  
      swap(&a, &b);
}

void swap(int *a, int *b) {
      int temp;
  
      temp = *a;
      *a = *b;
      *b = temp;
}

 

1. 최초 실행 시 다음과 같이 메모리가 할당된다.

 

2. swap() 함수를 호출한다.

이때 입력값으로 변수 a, b를 주소연산자를 이용해 &a, &b로 주소를 인자값으로 넘기기 때문에 swap() 함수가 호출되면, 다음과 같이 swap() 함수의 포인터 매개변수 *a, *b에 주소값들이 대입된다.

 

3. swap 함수 로직을 실행한다

변수 a 와 변수 b의 값을 서로 치환하는 로직인데, 이때 swap() 함수 내의 변수들은 포인터 변수이기 때문에 직접 메모리 주소를 참조해 전혀 다른 곳에 있는 main() 함수안에 있는 변수 a, b 값을 변경하게 된다.

 

자바는 Call by Value / Call by Address

원시값을 복사하느냐, 주소값은 복사하느냐에 따라 반환 결과가 달라지기 때문에 세간에서는 이 둘을 구분하기 위해 call by value / call by address 로 명명 지어 구분하기도 한다.

 

외부적인 관점에서 보면 주소값이 복사되든, 포인터를 이용해 참조하든, 메모리 안에 있는 데이터를 참조해 연산하는 동작 자체는 같기 때문에, 솔직하게 말하면 자바가 call by reference가 아니고 call by address 라 그러지만 사용하는 입장에서는 둘은 차이가 없다고 보면 된다.

 

기술 면접 질문 / 답안

Call by reference란 무엇이고 보통 어떻게 쓰이나요?

"Call by value"는 메소드에 변수를 전달할 때 해당 변수의 값이 복사되어 메소드 내에서 사용됩니다. 이 때문에 메소드 내에서 변수 값을 변경해도, 호출한 측의 변수에는 영향을 주지 않습니다. 반면, "Call by reference"는 메소드에 변수의 참조(메모리 주소)를 전달하여, 메소드 내에서의 변경이 호출한 측의 변수에도 영향을 줍니다. 하지만 자바에서는 기본적으로 "Call by value" 방식을 사용하며, 객체 참조가 값으로 전달됩니다. 즉, 자바는 진정한 의미의 "Call by reference"를 지원하지 않습니다.

스프링에서는 주로 객체 참조를 전달하여 메소드 호출을 처리합니다. 이 방식을 통해 메소드 내에서 객체의 상태를 변경 할 수 있으며, 이 변경은 호출한 측에서도 반영됩니다. 이런 방식은 객체 지향 프로그래밍의 장점을 활용하여, 상태 관리와 예측 가능한 코드 실행을 용이하게 합니다. 예를 들어, 빈(bean) 객체의 상태를 변경하면, 스프링의 다른 부분에서도 이 변경이 반영되어 일관성을 유지할 수 있습니다.






'항해 99 > Spring' 카테고리의 다른 글

Spring AOP  (0) 2024.04.09
Override, Overload / JPA 더티체킹 / JVM  (0) 2024.04.04
WebSocket 활용 웹 게임 구현  (0) 2024.04.03
WebSocket - 실제 코드 분석  (1) 2024.04.03
WebSocket - STOMP 2  (0) 2024.03.30