ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Call by Value / Reference
    JAVA 2022. 9. 1. 01:19

     

     

     

     

    Value / Reference

    Value는 값을, Reference는 참조를 뜻한다.

     

     

    바로 예시를 들어보자.

     

    int a = 5;
    Object obj = new Object();

     

    a는 5라는 '실제 값'을 할당받고,

    obj에 Object 인스턴스가 실제 존재하는 공간을 가리키는 '위치 정보'가 저장된다.

     

    쉽게 말하면, Object 인스턴스 자체의 내용은 다른 공간에 위치하고,

    인스턴스를 가리키는 주소가 obj 변수에 저장된다.

     

    이 과정에서 obj가 인스턴스를 '참조'한다고 하고,

    obj가 저장한 주소를 '참조값'이라고 한다.

     

     

    obj의 인스턴스 참조

     

     

    따라서 값을 직접 할당받는 자료형을 기본(원시) 타입(Primitive Type)이라고 하고,

    참조값을 가지는 자료형을 참조 타입(Reference Type)이라고 한다.

     

    기본 타입에는 [boolean, byte, short, int, long, float, double, char] 8종류가 있으며

    이 외에는 전부 참조 타입이라고 볼 수 있다.

     

     

     

    실험을 하나 해보자.

     

    int a = 5;
    int b = a;
    
    int a = 1;
    
    // so, b == ?

     

     

    b에는 a의 값을 할당해주었는데, a의 값이 변경된다면 b는 어떻게 될까?

     

     

    그대로 5이다.

    기본 타입은 값이 직접 할당되기 때문에 당연한 결과라 볼 수 있다.

     

     

     

     

    class Test {
        int value;
        
        Test(int data) {
            value = data;
        }
    }
    Test a = new Test(5); // a.value == 5
    Test b = a;
    
    a.value = 0;
    // so, b.value == ?

     

    그럼 위의 결과는 어떻게 될까?

     

    이전 예와 비슷하게 a의 내부 값만 바꿔주었다.

     

     

    b.value는 0이 된다.

    a.value만 바꿨을 뿐인데 b.value까지 바뀐 것이다.

     

    Test b = a;에서 b는 a의 참조값을 받았기 때문에 '같은 인스턴스'에 접근하게 되는 것이다.

     

     

     

     

     

     

     

     

    본론으로 들어오기까지 참 긴 과정이었다.

    여기까지 이해했다면 뒤의 과정도 이해가 쉬울 것이다.

     

     

     

    Call by Value / Reference

     

    Call by Value / Reference는 함수를 호출할 때 매개 변수의 값을 가져오냐, 주소를 가져오냐의 차이이다.

    public void swap(int A, int B) {
        int tmp = A;
        A = B;
        B = tmp;
    }
    public static void main(String[] args) {
      int a = 0;
      int b = 5;
          
      swap(a, b);
      
      // a == ?
      // b == ?
    }

     

    swap()은 두 수를 바꾸는 함수이다.

     

    Value와 Reference에 대해서 배웠으니 Call by ... 는 대충 감이 오지 않는가?

     

     

    먼저, Call by Value로 위 함수를 실행하면 main에서 결과는 어떻게 될까?

    a는 5가 되고, b는 0이 되지 않는다.

     

     

    어떻게 된 걸까?

    Call by Value는 변수의 값을 직접 가져오는 것이 아니다.

    '복사'해서 가져온다.

     

    즉, swap()의 변수 A와 main의 변수 a는 같지 않다.

     

     

     

    반면, Call by Reference로 함수를 실행하면 값이 바뀐다.

     

     

     

     

     

    Call by Value는 A = 0, B = 5로

    값이 복사되기 때문에 Main에서 swap()이 적용되지 않는다.

     

     

     

     

    Call by Reference는 A = a, B = b로

    Main의 a, b를 참조하기 때문에 a = 5, b= 0이 된다.

     

     

     

    결국 Call by Value는 Main은 swap()에게 값만 알려주는 것이고,

    Call by Reference는 Main이 swap()에게 실물을 빌려주는 것이다.

     

     

     

     

    Call by Reference 과정

    더보기

    조금 더 깊이 들어가 보자.

     

    함수가 호출될 때 메모리의 스택 영역에 함수를 위한 새로운 스택 공간을 만든다.

    Main 스택에서 swap()을 호출한다면, Main과는 다른 swap()이라는 새로운 스택이 생기는 것이다.

     

    스택끼리는 변수를 공유할 수 없기 때문에 실제 사용할 변수만 넘겨주어야 하는데, 이게 매개 변수이다.

     

    Call by Value는 값을 복사해서 넘겨주게 되고,

    Call by Reference는 값이 저장된 실제 메모리 주소를 넘겨주는 것이다.

     

     

     

    Main의 a, b가 다음과 같은 주소를 가진다고 하자.

    0x0001 a

    0x0002 b

     

     

    Call by Reference로 swap()을 호출하면 0x0001, 0x0002를 인자로 넘겨주게 된다.

    tmp = 0x0001(a)

    a = 0x0002(b)

    b = 0x0001(tmp)

     

    a와 b의 주소 자체가 바뀜으로써 a와 b의 값이 바뀌게 되는 것이다.

    ※ 자바는 포인터가 없기 때문에 위 예시는 무시하고 원리만 이해해주길 바란다.

     

     

    자바의 호출 방식

    더보기

    그렇다면 자바는 어떤 방식을 사용할까?

     

    밑의 예시를 보자.

    public void swap(Test a, Test b) {
        int tmp = a.value;
        a.value = b.value;
        b.value = tmp;
    }

    a.value와 b.value는 바뀌게 될까?

     

    바뀐다.

     

     

    매개 변수로 a와 b의 주소를 받고, 각 멤버 변수를 swap 했다.

    주소를 매개 변수로 받았으니 Call by Reference일까?

     

     

    한번 더 예시를 보자.

    public void swap(Test a, Test b) {
        Test tmp = a;
        a = b;
        b = a;
    }

     

    a와 b는 바뀔까?

     

     

    바뀌지 않는다.

     

     

    왜일까?

    결론 먼저 말하자면 자바는 Call by Reference가 없다.

    즉, 자바에는 Call by Value만 존재한다.

     

    a와 b의 참조값을 '복사' 해서 넘겨준 것이기 때문이다.

     

     

    참조값을 복사해서 받았지만 참조값이기 때문에 객체 내부에 접근할 수 있고,

    복사해서 받았기 때문에 a와 b는 서로 바뀌지 않는다.

    'JAVA' 카테고리의 다른 글

    Garbage Collector  (0) 2022.08.26
    자바 메모리 구조  (0) 2022.08.26
    Java Virtual Machine  (0) 2022.08.24

    댓글

Designed by Tistory.