본문 바로가기

gyub's 공부일기/Java

[ JAVA ] 자바는 call by value? call by reference?

결론: 자바는 call by value입니다

=> Call by reference는 원본의 주소값을 전달하므로, 원본을 변경할 수 있습니다. 왜냐하면 주소값을 통해 원본에 접근할 수 있기 때문입니다. 

자바에는 포인터 같은 변수의 주소값을 추출 및 저장하는 기능이 없습니다. 그렇기에 call by reference가 될 수 없습니다.

 

 

(아래 글은 참조에 관해 이해를 하시고 나서 보는 걸 추천드립니다.)

2021.03.24 - [gyub's 공부일기/Java] - [ JAVA ] 참조란?

 

Call By Value ( 값에 의한 호출 )

Call By Value는 원본 값을 그대로 복사하여 매개변수로 전달하는 것입니다.

 

public class JavaIsCallByValue {

    public static void main(String[] args) {

        int a = 1;
        int b = 3;

        System.out.println("swap 전 a:" + a + " " + "b:" + b);
        swap(a, b);
        System.out.println("swap 후 a:" + a + " " + "b:" + b);
    }

    private static void swap(int x, int y) {
        int tmp = x;
        x = y;
        y = tmp;
    }
}

 

 

위에서의 출력 결과는 어떻게 될까요?

 

 

swap메서드를 호출 했음에도 값이 전혀 바뀌지 않았죠.

왜 이러는 것일까요??

위의 그림에서 보이듯이 x와 y 그리고 a 와 b는 서로 다른 메모리 주소를 갖고있습니다.

그러므로 실제 a와 b의 값이 변경되는 것이 아닌 x와 y의 값만 변경되는 것이죠

좀 더 자세히 말하자면 a와 b를 매개변수로 swap메서드를 호출 했을 때, a와 b의 값이 복사되어져 x와 y에 값에 들어가있고 이 복사된 값들을 이용해 x와 y의 값을 변경한 것 뿐입니다.

 

그러니 원본인 a와 b의 값은 변경될 리 없죠.

이번엔 primitive type이 아닌 reference type으로 다시볼게요.

 

public class JavaIsCallByValue {

    public static void main(String[] args) {

        Num numA = new Num(1);
        Num numB = new Num(3);
        System.out.println("swap 전 numA:" + numA.num + " " + "numB:" + numB.num);
        swap(numA, numB);
        System.out.println("swap 후 numA:" + numA.num + " " + "numB:" + numB.num);
    }

    private static void swap(Num numX, Num numY) {
        Num tmp = numX;
        numX = numY;
        numY = tmp;
    }

    public static class Num {
        int num;

        public Num(int num) {
            this.num = num;
        }
    }
}

위의 출력결과는 어떻게 될까요?

변함이없습니다.

만약 call by reference였다면 둘의 값이 변경되어야 하는 것이 맞는거죠.

좀 더 자세히 설명하자면 위의 코드는 Num이라는 클래스를 선언하고 각각 1과 3의 필드값(num)을 가진 인스턴스를 생성했어요.

그 후 swap메서드를 통해 두 개의 참조를 바꿨죠. 하지만 둘의 필드값은 변하지 않았어요. 자바가 call by reference였다면 이 둘의 참조도 바뀌며 값도 함께 변경이 됐어야 하는것입니다.

 

하지만 자바가 call by value냐 call by reference에 대한 의견이 갈리는 것은 아래의 예제 때문인데요.

 

public class JavaIsCallByValue {

    public static void main(String[] args) {

        Num numA = new Num(1);
        Num numB = new Num(3);
        System.out.println("swap 전 numA:" + numA.num + " " + "numB:" + numB.num);
        swap(numA, numB);
        System.out.println("swap 후 numA:" + numA.num + " " + "numB:" + numB.num);
    }

    private static void swap(Num numX, Num numY) {
        int tmp = numX.num;
        numX.num = numY.num;
        numY.num = tmp;
    }

    public static class Num {
        int num;

        public Num(int num) {
            this.num = num;
        }
    }
}

 

위의 출력 결과는 

이렇게 필드값이 변경되었습니다. 그렇다면 이건 왜 그러는걸까요?

자바가 call by reference가 아닌 이유가 필드값이 변경이 안 됐기 때문이라고 한 것 같은데..

 

이런 예외적인 경우는 자바가 함수의 인자로 전달해주는 것은 복사된 참조 값을 전달하기 때문인데요.

즉, 참조값을 받아서 그 참조값을 이용하는 것은 가능하기에 각각의 필드값이 변경되는 것입니다.

 

긴 글 읽어주셔서 감사합니다.

반응형

'gyub's 공부일기 > Java' 카테고리의 다른 글

[ JAVA ] 참조란?  (3) 2021.03.24
[JAVA] JVM 클래스로더  (0) 2020.12.10
[ JAVA ] JAVA의 동작 방식와 JVM 메모리 구조  (0) 2020.11.30
[ JAVA ] Java의 특징 및 JVM, JDK, JRE  (0) 2020.11.29