HwangHub

[Java] call by value, call by reference 본문

DEV-STUDY/Java

[Java] call by value, call by reference

HwangJerry 2023. 7. 2. 16:26

자바에서는 별도로 사용자가 포인터를 다루지 않기 때문에 함수 호출시 파라미터 값들은 함수의 지역 변수에 복사되어 넘어가게 된다. 이러한 과정을 "call by value"라고 칭하며, 자바는 call by value 방식으로 함수를 수행한다.

만약 인자를 통해 배열 또는 객체를 넘겼는데, 해당 객체 자체가 아예 파라미터를 통해 넘어가는 경우를 "깊은 복사"라고 하며, 이러한 방식으로 수행되는 인자 매커니즘을 "call by reference"라고 한다.

 

JVM 이해하기 : Stack과 Heap

기본적으로 지역 변수들은 stack에 저장되는데, primitive type의 변수와 값은 stack에 한번에 저장된다. 하지만 객체나 배열처럼 reference type은 동적으로 메모리를 할당해야 하므로 heap에 해당 value가 저장되고, 그 주소값이 stack에 저장된다.

 

public class Main {
    public static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
        System.out.println(a + " " + b); // 20 10
    }

    public static void main(String[] args) {
        int n = 10, m = 20;
        swap(n, m);
        System.out.println(n + " " + m); // 10 20
    }
}

위 코드를 수행한 결과는 주석과 같다. swap을 수행하면 겉으로 보기엔 n과 m의 값이 바뀌어야 하는 것 아닌가 할 수 있는데, 이는 자바가 call by value 방식으로 함수를 수행하기 때문에 위와 같은 결과가 나오는 것이다.

 

위 코드 중 swap 함수 선언 부분을 보면, 파라미터로 int a와 int b가 정의되어 있다. 즉, swap 함수를 호출할 때 arguments로 n, m을 입력하였다 하더라도 이는 엄격히 int a와 int b에 n과 m의 값을 call by value 방식으로 넘기게 된다.

 

다시 말하면, main함수를 수행할 때 지역 변수인 int n, int m은 main 함수 수행 중의 stack 영역에 10, 20으로 각각 저장되고, swap 함수가 호출될 때 swap 함수의 지역 변수에 int a = 10, int b = 20로 복사되어 swap 함수에게 주어진 stack 영역에 저장되므로, swap 함수를 통해 a와 b의 값을 switch한다 하더라도 n과 m은 변동이 없는 것이다.

 

즉, 위 코드를 수행하더라도 출력 값은 주석과 같이 되는 것이다.

 

위 과정을 감안하면 아래 코드의 수행 결과 또한 쉽게 이해할 수 있다.

class IntWrapper {
    int value;

    public IntWrapper(int value) {
        this.value = value;
    }
}

public class Main {
    public static void modify(IntWrapper n, IntWrapper m) {
        n.value = 50;
        m = new IntWrapper(60);
        System.out.println(n.value + " " + m.value); // 50 60
    }

    public static void main(String[] args) {
        IntWrapper n = new IntWrapper(10);
        IntWrapper m = new IntWrapper(20);
        modify(n, m);
        System.out.println(n.value + " " + m.value); // 50 20
    }
}

IntWrapper 타입의 값은 heap에 저장되어 있는 주소값이며, 이 것이 지역 변수로 할당되었으므로 stack에 저장된다. modify 함수의 파라미터 이름과 main 함수의 지역변수 이름이 동일하여 헷갈릴 수 있지만, 이는 엄연히 stack 내에서 다른 영역에 저장된다. 하지만 위의 과정에서 IntWrapper들은 stack에 담고 있던 값이 heap 영역에 있는 주소값이었기에, main 함수의 Intwrapper n이 갖고 있던 주소값이 modify 함수의 IntWrapper n에 '복사'되더라도, heap에 저장되어 있는 값을 수정할 수 있는 것이다.

만약 reference type을 파라미터로 받는 함수를 만들 때, 함수 내에서의 수행 로직에 의해 원래의 reference type 변수의 값이 변동되길 원하지 않는다면 .clone()을 사용하면 된다.

 

결론

위와 같은 JVM의 매커니즘을 이해하고 있는다면 자바가 call by reference로 수행된다는 오해를 하지 않을 수 있게 된다.

 

'DEV-STUDY > Java' 카테고리의 다른 글

[Java] scope rule  (0) 2023.07.03
[Java] Immutable한 문자열  (0) 2023.07.02
[Java] 숫자 character의 아스키 코드  (0) 2023.07.01
[Java] 문자열의 .charAt(), .length() 메서드  (0) 2023.06.30
[Java] 배열 선언시 초기화  (0) 2023.06.30
Comments