Home Call by Value, Call by Reference
Post
Cancel

Call by Value, Call by Reference

Call by Value, Call by Reference

함수의 매개변수에서 값을 복사 또는 주소값을 참조 하는 것에 따라 반환 결과가 달라진다. 자바의 데이터형을 알아보면 크게 두가지로 나뉘게 된다.

  • 기본형
    • Boolean Type(boolean), Numeric Type(short, int, long, float, double, char)
  • 참조형
    • Class Type, Interface Type, Array Type, Enum Type, 기본형을 제외한 모든 것들
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Main {
    public static void main(String[] args) {

        int var = 1;
        int[] arr = { 1, 2, 3 };

        // 변수 자체를 보냄 call by value
        add_value(var);
        System.out.println(var); // 1 : 값 변화가 없음

        // 배열 자체를 보냄 (call by reference)
        add_reference(arr);
        System.out.println(Arrays.toString(arr)); // 101, 102, 103 : 값이 변화함
    }

    static void add_value(int var_arg) {
        var_arg += 100;
    }

    static void add_reference(int[] arr_arg) {
        Arrays.setAll(arr_arg, i -> arr_arg[i] + 100);
    }
}

1. Call by Value

Call by Value는 메서드를 호출할 때 값을 넘겨주기 때문에 Pass by Value라고도 부른다.
메서드를 호출하는 호출자(Caller)의 변수와 호출 당하는 수신자(Calle)의 파라미터는 복사된 서로 다른 변수이다.
값만을 전달하기 때문에 수신자의 파라미터를 수정해도 호출자의 변수에는 아무런 영향이 없다. 그래서 위의 var 변수가 변화가 없는 것이다.

2. Call by Reference

Call by Reference는 참조(주소)를 직접 전달하여 Pass By Reference라고도 부른다.
참조를 직접 넘기기 때문에 호출자의 변수와 수신자의 파라미터는 완전히 동일한 변수이다. 메서드 내에서 파라미터를 수정하면 그대로 원본 변수에도 반영된다. 그래서 위의 arr 변수에도 변경된 값으로 변화하게 된다.

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

Call by Value 과정

1. main 스택 프레임에 두 변수가 담기게 된다.

image

Java에서 변수를 선언하면 Stack 영역에 할당된다.


원시타입(Primitive Type)은 Stack 영역에 변수와 함께 저장되며, main 스택 프레임에 저장된다.


참조타입(Reference Type) 객체의 실제 데이터는 Heap 영역에 저장되고 이를 참조할 주소값을 Stack 영역에 저장하게 된다.

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

2. add_value() 메서드 - call by value

image

  1. add_value() 메서드가 호출되면서, add_value 스택 프레임이 생성되고 그 안에 지역 변수(매개변수) var_arg가 값을 1을 받은채 생성되게 된다.
  2. 그리고 자체 메서드 로직으로 100을 더해 값은 101이 된다.


add_value 스택 프레임 안에 있는 변수 var_arg가 바뀐 것이지, main 스택 프레임 안에 있는 변수 var가 바뀐 것이 아니다.
매개 변수 var_args는 그저 변수 var로 부터 원시값을 복사하여 받은 것 뿐이다.(call by value) 즉, 메인에 정의 되어 있는 var변수와 add_value메서드에 정의되어 있는 var_arg변수는 서로 다른 것이다.

3. add_reference() 메서드 - call by reference

image

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


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


핵심 키워드 : 값, 참조, 복사, 객체 전달 / 값 전달


나의 답
자바에서는 Call by Refernce 개념이 없다.
왜냐하면 C와 달리 자바에서는 포인터를 철저하게 숨겨 개발자가 직접 메모리 주소에 접근하지 못하게 조치했기 때문이다. 자바에서의 파라미터는 Call by Value로서만 동작되며, 원시값이 복사 되느냐 주소값이 복사되느냐 차이가 있을 뿐이다.
그리고 매개변수에 복사된 값에 따라, 원시값이면 바로 연산을하고 주소값이면 해당 메모리 주소를 참조해 값을 가져와 연산한다.


모범 답안
java의 경우 call by reference란 함수에 매개변수를 전달할 때 값 만을 복사하여 전달하는 것이 아니라 객체의 주소를 전달하는 것을 의미합니다. 이렇게 객체의 주소를 전달하게 되면 함수 내에서 객체의 주소값을 통해 힙 메모를 참조하여 실제 객체의 값의 영향을 줄 수 있습니다. 주로 함수 내에서 연산한 것이 함수 밖에서도 반영되기를 기대할 때 사용합니다.
java의 경우 객체를 call by value 방식과 같이 객체 내부의 값들을 모두 복사해서 전달하는 선택지가 없고, primitive 타입에는 주소가 없어 call by value 방식으로 전달됩니다.



참고