본문 바로가기
프로그래밍/JAVA 내용정리

[JAVA] JAVA는 Call by Value일까요? Call by Reference 일까요?

by 노잼인간이라불립니다 2023. 5. 28.

오늘의 주제

JAVA는 Call by Value일까요? Call by Reference일까요?

 

결론 부터 말씀드리면 JAVA는 Call by Value방식입니다.


목차

0. 개요

1. Call by Reference는 무엇일까?

2. Call by Value는 무엇일까?

3. Call by Reference와 Call by Value는 뭐가 다르지?

4. JAVA는 Call by Reference일까? Call by Value일까?

5. 요약 및 정리

 


0. 개요

 필자는 오늘 문득 친구에게서 JAVA는 Call by value일까? Call by reference일까? 질문을 받았어요. 질문을 받았을 때에는 JAVA는 두 가지 방법을 다 쓰는게 아닐까? 생각했어요. 그리고 지금까지는 그렇게 믿고 있었구요. 그러나 현실은 냉혹했어요. 내가 지레짐작으로 알고 있었던 것이 사실은 아니었던 것이죠. 그래서 이 글을 작성하는 거에요.

 

 Call by Value, Call by Reference는 매개 변수 전달 메커니즘이에요.(이 외에도 다른 메커니즘도 존재해요.) 먼저 이 둘의 개념에 대해 살펴볼거에요. 그리고 이 둘의 차이점을 알아보고, 마지막으로는 언어 마다 함수 또는 메서드에 매개 변수를 전달하는 방식이 다른데, JAVA에서는 어떤 메커니즘을 채택하고 있는지 알아 볼 거에요.

 

1. Call by Reference는 무엇일까?

 Call by Reference................... Pass by Reference 라고도 불리죠. 이 단어들을 곰곰히 생각해봅시다... 직역하자면 "참조에 의해서 무엇인가가 호출되거나(불러지거나) 통과된다?" 라는 의미 정도로 해석할 수 있겠어요. 그럼 여기서 Call 되는 것은 뭘까요????? ....... 추측하건데 변수로 선언되어 있는 메모리에 저장되어 있는 하나의 데이터라고 추측할 수 있어요.

 

 지금 까지의 내용을 정리하자면... "변수로 선언된 메모리에 저장되어 있는 데이터를 메서드에 넘겨주어야 하는데, Reference 방식으로 넘겨주는 메커니즘이 Call by Reference 이다" 정도 까지 정리가 되었을거에요. (데이터를 메서드에 넘겨주어야 하는 이유는 메서드에서 데이터를 이용하여 로직 구현이 필요하기 때문일거에요.) 그럼 이 "Reference 방식" 이라는 건 도대체 뭘까요? 매우 궁금해요. 뭘까? 뭐지? 뭐길래 날 힘들게 하는거지?

 

 - "Reference 방식" 이라는 건 도대체 뭘까요?

 영어를 좀 하신다 하시는 분은 Reference라는 단어에서 느낌이 오신 분들도 계실꺼에요.(전 전혀 안 왔어요. ㅠㅠ) 결론부터 말씀드리면  "Reference 방식은 값을 copy 하지 않고 Original Data를 바로 가져다 쓰는 방식이에요!". 이 문장만 읽고 바로 이해가 되시나요? 이해가 된다고 하면 축해해요! 당신은 천재에요!

 

 그러나 대부분이 이해가 잘 안되실꺼에요. 그래서 제가 그림을 준비했어요. 같이 보면서 이해도를 높여 봅시다!

 

위와 같이 main 함수에 변수 x가 선언되어 있고, 함수 f1에 변수 x를 매개변수로 전달하여 호출하게 되었을 경우 최종적으로 x의 값은 1일까요? 10일까요????  정답을 말씀드리면 만약 매개 변수 전달 매커니즘이 Call by reference 방식이면 x값은 10이 됩니다. 그 이유는 위에서 말씀드린 "Reference 방식은 값을 copy 하지 않고 Original Data를 바로 가져다 쓰는 방식" 이기 때문인데요. Original Data를 가져다 쓴다는 것은 x와 x1은 같은 주소값에 들어있는 value를 공유하게 된다는 말과 동일합니다. 그렇기 때문에 한 쪽에서 이 값을 수정하게 된다면 다른 값에도 영향이 미치는 현상이 발생하는 것이죠.

 

2. Call by Value는 무엇일까?

 그렇다면 Call by Value는 무엇일까요? 위와 마찬가지로 직역해보자면 "값에 의해 무엇인가가 호출되거나(불러지거나) 통과된다?" 라고 해석할 수 있겠어요. 위와 동일하게 지금까지의 내용을 정리해보자면.... "변수로 선언된 메모리에 저장되어 있는 데이터를 메서드에 넘겨주어야 하는데, Value 방식으로 넘겨주는 메커니즘이 Call by Value이다" 정도 까지 정리가 되었을거에요.

 

 그럼 코드와 그림으로 함께 살펴볼게요!!

public class Main {
    public static void main(String[] args) {

        // 1. 변수를 선언하여 데이터를 메모리에 저장합니다.
        int x = 10;

        // 2. x값을 인수로 전달하여 println 메서드를 호출합니다.
        System.out.println("x = " + x);

        // 3. x값을 인수로 전달하여 plusOne 메서드를 호출합니다.
        plusOne(x);

        // 4. x값을 인수로 전달하여 println 메서드를 호출합니다.
        System.out.println("x = " + x);
    }

     public static void plusOne(int x){

        // f1. 기존의 x값에 1을 더합니다.
        x = x + 1;

        // f2. x값을 인수로 전달하여 println 메서드를 호출합니다.
        System.out.println("x = " + x);
    }
}

 위와 같은 코드가 있다고 합시다. 2번, f2번 , 그리고 4번의 실행 값의 결과가 예상이 되시나요? 만약 자바가 Call by Value 방식으로 동작하고 있다는 걸 알고 계신다면 손쉽게 추론이 가능할 것 같아요!

 

2번 실행 시: 10

f2번 실행 시: 11

4번 실행 시: 10

 결과 값은 위와 같아요. 그런데 결과값을 보니 Call by Reference와 큰 차이점이 보이시나요?? 이 차이점을 캐치하셨다면 축하해요! 당신은 두 가지 매개변수 전달 매커니즘을 100% 이해한 거에요!! 결론적으로 Call by Value 방식은 메서드에 매개변수를 전달할 때 값을 복사해서 전달하기 때문에 Original x 값은 10으로 남아 있는 반면 매개변수로 넘겨준 x 값은 11로 값이 변경되었어요.

 

3. Call by Reference와 Call by Value는 뭐가 다르지?

 지금까지 Call by Reference 방식과 Call by Value 방식 두 개다 어떤 방식으로 메서드에 매개변수를 전달하는지 알아 보았어요. 조금은 이해가 되셨을 것이라고 생각합니다.

 Call by Reference 방식과 Call by Value 방식의 가장 큰 차이점은 Original data를 매개변수로 넘겨주느냐, 아니면 데이터를 복사해서 변수로 넘겨주느냐인 것 같아요.

 

4. JAVA는 Call by Reference일까? Call by Value 일까?

 그렇다면 저의 주 언어인 JAVA는 Call by Reference 일까요? Call by Value 일까요? 두번째 섹션의 코드의 동작방식으로 살펴보면 Call by Value 방식임을 손쉽게 예상해볼 수 있어요. 그럼 좀 더 살펴볼까요?

public class Main {
    public static void main(String[] args) {

        // 1. 변수를 선언하여 데이터를 메모리에 저장합니다.
        int x = 10;

        // 2. x값을 인수로 전달하여 println 메서드를 호출합니다.
        System.out.println("x = " + x);

        // 3. x값을 인수로 전달하여 plusOne 메서드를 호출합니다.
        plusOne(x);

        // 4. x값을 인수로 전달하여 println 메서드를 호출합니다.
        System.out.println("x = " + x);
    }

     public static void plusOne(int x){

        // f1. 기존의 x값에 1을 더합니다.
        x = x + 1;

        // f2. x값을 인수로 전달하여 println 메서드를 호출합니다.
        System.out.println("x = " + x);
    }
}

 

 JAVA에서 Primitive 타입을 변수로 선언했을 경우 변수는 Stack 영역에 저장됩니다. 위 코드에서는 main이 실행되고 stack frame에는 x라는 변수가 10으로 저장이 됩니다. 그리고 plusOne이 실행될 경우 넘겨지는 매개변수는 기존 x변수의 값을 복사하여 plusOne메서드로 넘겨지게 됩니다. 이 변수는 지역변수로써 메서드가 종료되면 사라지는 변수입니다.

 즉 현재 스택 프레임에 저장된 x = 11이란 값은 plusOne이라는 메서드가 종료가 되면 gc에 의해 사라질 거에요. 정리하자면 JAVA에서는 메서드에 매개변수를 전달할 때 변수의 Original은 가져다 전달하는 것이 아닌, Original 값만 복사하여 매개변수로 전달하는 방식을 채택하고 있습니다.

 

5. 요약 및 정리

 마지막으로 몇 가지 중요한 점을 요약 및 정리하고자 합니다.

1. Call by ReferenceOriginal Data를 매개변수로 전달한다. 즉, 매개변수로 전달된 값이 변하면, 원래의 값도 변한다.

2. Call by Value는 Original Data의 복사본을 매개변수로 전달한다. 즉, 매개변수로 전달된 값이 변해도 원래의 값에는 영향을 끼치지 않는다.

3. JAVA는 Call by Value 방식을 채택하고 있다.

 

Reference

https://www.baeldung.com/java-pass-by-value-or-pass-by-reference