Java

Call By Value & Call By Reference

iksadnorth 2023. 7. 17. 16:56

👣 개요

두 개념 모두 메소드를 실행하기 전에 메소드의 Parameter를 넘길 때의 방법에 대한 것이다.
public static void transform(int func_digit, SomeThing func_instance) {
    func_digit = 10;
    func_instance.setId(10);
}

public static void main(String[] args) {
    SomeThing instance = new SomeThing();
    instance.setId(5);
    int digit = 5;
    
    transform(digit, instance);
    
    System.out.println(digit);
    // output : 5
    System.out.println(instance.getId());
    // output : 10
}
위 예시를 보면 transform 함수에 digit라는 변수가 입력되었을 때,
메모리의 주소가 그대로 함수에 전달되었다면 값의 변경이 이뤄야 했을 것이다.

하지만 Java는 파라미터로 변수를 전달할 때,
같은 값을 가진 변수를 복사해서 복사본을 전달하기 때문에
원본의 값이 때때로 원본의 값이 훼손되지 않는다.
이와 같이 함수의 파라미터원본을 줄지 복사본을 줄지에 관한 방법론이
Call By Value & Call By Reference라고 할 수 있다.

👣 메모리 값 & 메모리 주소값

위 개념들을 이해하기 위해선 '메모리 값'과 '메모리 주소값' 개념의 차이를 명확히 해야 한다.
예를 들어 다음과 같은 코드가 있다고 가정한다.
// 메모리 주소값 : 1u3hsd934
int a = 100;
메모리에 실제로 저장된 값은 100이고 이런 100이라는값이 저장된 메모리의 고유 번호는 1u3hsd934이다.
이 두가지의 차이를 유념하고 다음 설명을 들으면 된다.

👣 Call By Value

Call By Value는 함수에 값을 전달할 때, 복사본을 전달한다.
public static void transform(int func_digit) {
    // func_digit의 주소값 : aw14e21
    func_digit = 10;
}

public static void main(String[] args) {
    // digit의 주소값 : 24cj35e
    int digit = 5;
    
    // digit의 주소값 : 24cj35e
    transform(digit);
    
    // digit의 주소값 : 24cj35e
    System.out.println(digit);
    // output : 5;
}
위 코드에서 볼 수 있듯이 비록 transform 함수에 24cj35e 위치의 digit 변수값을 전달했지만
실제로 함수에서 사용하고 있는 변수 주소값은 aw14e21 이다.
이처럼 함수로 들어온 값은 해당 메모리를 직접 들여서 오는 것이 아니라
해당 메모리값을 다른 메모리 주소에 복사해서 입력하게 된다.
public static void transform(SomeThing func_instance) {
    // func_instance 주소값 : aqwer1234
    // func_instance 값 : dhe1n4fo
    func_instance.setId(10);
}

public static void main(String[] args) {
    // instance 주소값 : rewq4321
    // instance 값 : dhe1n4fo
    SomeThing instance = new SomeThing();
    instance.setId(5);
    
    // instance 주소값 : rewq4321
    // instance 값 : dhe1n4fo
    transform(instance);
    
    // instance 주소값 : rewq4321
    // instance 값 : dhe1n4fo
    System.out.println(instance.getId());
    // output : 10
}
착각하기 쉬운 것이 무조건 원본 데이터를 훼손할 수 없다고 생각할 수 있는데
위 예시는 데이터값이 훼손될 수 있음을 보여주는 예시이다.
물론 Call By Reference에 의해 함수에 입력되는 값은 복사본이 전달된다.
하지만 전달된 값 자체가 이미 객체 주소값이기 때문에
해당 객체에 대해 접근할 수 있게 되어 훼손 가능성에 놓이게 된다.
위와 같은 훼손 가능성 자체까지 차단하고 싶다면 Deep Copy를 해 변수를 전달해야 한다.

👣 Call By Reference

Call By Reference는 함수에 값을 전달할 때, 원본 그대로를 전달한다.
이는 C 언어의 포인터로 구현될 수 있다.
void func(int *n) {
    // n 주소값 : 12hyv24
    // n 값 : 20
    *n = 20;
}

void main() {
    // n 주소값 : 12hyv24
    // n 값 : 10
    int n = 10;
    
    func(&n);
    
    // n 주소값 : 12hyv24
    // n 값 : 20
    printf("%d", n);
}
C 언어는 포인터를 이용해서 변수 주소값을 그대로 넘길 수 있기 때문에
이런 특성을 항상 유념하며 변수를 변경해야 한다.

'Java' 카테고리의 다른 글

Auto Boxing & Auto UnBoxing  (0) 2023.07.17
문자열  (0) 2023.07.17
JDK, JRE, JVM  (0) 2023.07.17
Garbage Collector  (0) 2023.07.17
Java 코드 작성부터 실행까지  (0) 2023.07.17