본문 바로가기
Java/topic

Java의 Call by value(Pass by value), Swap 구현 방식 4가지

by Ellery 2022. 10. 9.

C++에서의 swap() 유틸리티 함수는 주소값을 교환하는 call by reference 방식으로서 동작한다. tmp 변수를 중간 매개로 주소값(값의 위치)을 서로 교환한다.

void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

Java에서 primitive type, reference type에 해당하는 값을 저장하는 방식에 차이가 있다.

  • JVM 메모리에서 primitive type은 stack 영역에 저장된다
  • reference type은 그 객체인 값이 heap 영역에 저장되고, stack 영역에 있는 변수가 객체의 주소값을 가지고 있다.

만약 swap 메서드에서 reference 변수를 파라미터로 넘기게 되면 해당 객체를 가리키는 새로운 변수가 stack 영역에 정의가 된다.
새롭게 만들어진 변수의 주소값을 서로 교환하거나, 값을 변경한다고 해서 기존의 변수값이 변하지 않는다.
그렇기 때문에 Java는 항상 call by value(pass by value) 방식으로 동작한다고 할 수 있다.

Call by value와 Call by reference의 차이

Call by value 방식의 메서드 호출 방식에서 메서드 호출자(caller)와 호출당하는 수신자(callee)의 파라미터는 복사되어서 서로 다른 변수이다. 따라서 수신자의 파라미터를 수정해도 호출자의 변수가 바뀌지 않는다.

call by reference 방식은 참조(주소)를 직접 전달하기 때문에 caller의 변수와 callee의 파라미터가 완전히 동일한 변수이다. 수신자의 파라미터를 수정하면 호출자의 변수도 바뀐다.

기본적으로는 Reference type을 이용해서 swap을 구현해야하지만, primitive 변수 값을 교환하는 트릭도 있다. 참고로 Collections 패키지에서 list 내의 원소값 간의 swap 메서드를 지원한다.

 

방식1. Swapping primitives - swap 메서드에서 b, a를 대입한 b를 파라미터로 넘겨주고 받은 리턴값 b를 a에 대입한다

class Main {
    public static int swap(int... args) { return ags[0]; }

    public static void main(String[] args) {
        int a = 5;
        int b = 10;
        a = swap(b, b = a); // a = 10, b = 5        
    }
}

방식2. Swapping array elements - 교환할 값이 배열의 요소이면 배열인덱스로 접근해서 교환하는 메서드를 짤 수 있다.

class Main {
    public static void swap(int[] arr int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void main(String[] args) {
        int[] arr = { 1, 2, 3, 4, 5 };
        swap(arr, 2, 3);
    }
}

방식3. Swapping Objects, AtomicInteger - 객체로 wrapping해서 내부 값을 교환하는 방식

class Main {
    public static void swap(IntRef a, IntRef b) {
        int tmp = a.val;
        a.val = b.val;
        b.val = tmp;
    }

    public static void main(String[] args) {
        IntRef a = new IntRef(5);
        IntRef b = new IntRef(10);
        swap(a, b); // a.val = 10, b.val = 5
    }
}
import java.util.concurrent.atomic.AtomicInteger;

class Main {
    public static void swap(AtomicInteger a, AtomicInteger b) {
        a.set(b.getAndSet(a.get()));
    }

    public static void main(String[] args) {
        AtomicInteger a = new AtomicInteger(5);
        AtomicInteger b = new AtomicInteger(10);
        swap(a, b);
    }
}

방식4. Collections.swap(list, i, j);
- public static void swap(List<?> list, int i, int j) 메서드로 2번 방식과 유사하게 사용할 수 있다.