자바는 항상 Call-By-Value(Pass-By-Value)로만 동작한다고 한다.

분명 자바를 처음 배울때는 Call-By-Value와 Reference-By-Value를 모두 사용한다고 배웠던거 같은데 어떻게 된건지 알아보겠다.

(Call-By-Value와 Pass-By-Value에서 Call과 Value는 거의 동일하게 사용한다고 하니 Call-By-Value로 통일하여 작성하기로 한다.)


일단 처음 Call-By-Value와 Reference-By-Value를 학습할 때 배우는 swap 예제를 살펴본다.

 

아래는 Call-By-Value의 예시로 작성된 코드이다.

a,b 변수를 swap 함수의 인자로 건네줘서 값을 바꿨지만 a, b 변수의 값은 그대로이다. 즉, a, b의 값만 복사(Call-By-Value)하여 x, y 변수가 지역변수로 새로 생성됐기 때문에 x와 y를 스왑하던, 값을 바꾸던 a, b 변수에는 영향이 없는 것이다. 

public class CallByTest {
    @Test
    public void callbyvalue(){
        int a = 10;
        int b = 20;

        System.out.println("swap() 호출 전 : a = " + a + ", b = " + b); // a = 10, b = 20
        swap(a, b);
        System.out.println("swap() 호출 후 : a = " + a + ", b = " + b); // a = 10, b = 20
    }

    public void swap(int x, int y){
        int temp = x;
        x = y;
        y = temp;
    }
}

 

그럼 Call-By-Reference 예제로 배웠던 swap 예제코드를 살펴본다.

swap 호출전후로 인자로 넘겼던 객체의 상태값이 바꼈으므로 Call-By-Reference의 예시로 알았던 코드이다.

public class CallByTest {
    @Test
    public void CallByReference(){
        Game a = new Game(10);
        Game b = new Game(20);

        System.out.println("swap() 호출 전 : a.star = " + a.star + ", b.star = " + b.star); // a.star = 10, b.star = 20
        swap(a, b);
        System.out.println("swap() 호출 후 : a.star = " + a.star + ", b.star = " + b.star); // a.star = 20, b.star = 10
    }

    public void swap(Game x, Game y){
        int temp = x.star;
        x.star = y.star;
        y.star = temp;
    }

    class Game {
        int star;
        public Game(int star) {
            this.star = star;
        }
    }
}

 

하지만, 진정한 Call-By-Reference는 참조하는 객체의 상태값을 변경하는게 아니라 실제 x,y 변수가 참조하는 객체를 변경하여 외부의 a 변수가 참조하는 객체를 바꿀수 있는 경우를 말한다.

자바는 Call-By-Value만 지원하므로 아래 코드에서는 a가 참조하는 객체가 realCallByReference() 함수에서 변경한 객체(star 값이 20인)로 변경되지 않고 여전히 10이 출력되는 걸 볼 수있다.

public class CallByTest {
    @Test
    public void test(){
        Game a = new Game(10);

        realCallByReference(a);

        System.out.println("a가 참조하는 객체는 바뀌지 않음 : " + a.star); // 10
    }

    public void realCallByReference(Game x){
        x = new Game(20);
    }
}

1. 함수 내에서 지역변수 x가 새로 생성되며 함수인자인 a와 같은 객체를 참조함.

    > Call-By-Value에 의해 a가 참조하는 객체에 대한 위치값만 전달해줬음.

2. realCallByReference 함수내에서 x가 참조하는 객체를 신규로 생성한 객체로 변경함.

    > a와 같은 객체를 참조하다가 새로운 객체로 변경되었으며 a에는 전혀 영향없음.

3. realCallByReference 함수 종료후 출력결과를 보면 a는 그대로 기존 객체를 참조하고 있음.

 


정리해보면

자바는 Call-By-Value만을 지원한다. 

처음 학습시 Call-By-Reference의 예제로 알고있던 swap코드는 참조하는 객체의 상태값을 바꾸는 것이지 참조하는 객체 자체를 바꾸는 것이 아니므로 진정한 Call-By-Reference의 예제는 아니다.

 

참고 StackOverflow

stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

 

Is Java "pass-by-reference" or "pass-by-value"?

I always thought Java uses pass-by-reference. However, I've seen a couple of blog posts (for example, this blog) that claim that it isn't (the blog post says that Java uses pass-by-value). I don't ...

stackoverflow.com

 


 

 

 

+ Recent posts