Tiny Star

🪄Interview/✏️Study

[CS STUDY INTERVIEW] 2주차 - Call by value와 Call by reference

청크 2024. 2. 19. 17:39

CS 스터디 2주차

 

자바에서의 Call by value와 Call by reference는 매개변수를 전달하는 방식에 관한 용어이다.

자바에서의 함수 호출 방식

자바에서의 함수 호출 방식은 전달되는 인자의 데이터 타입에 따라 달라진다.

 

1. 원시 자료형(primitive type) : 값에 의한 호출 (Call by value)

: int, short, long, float, double, char, boolean과 같은 원시 자료형 즉 기본형들은 값을 복사하여 함수에 전달된다.

 

2. 참조 자료형(reference type) : 주소 값(참조 값)에 의한 호출 (Call by reference)

: 배열이나 클래스 인스턴스와 같은 참조 자료형은 해당 객체의 주소 값이 복사되어 함수에 전달된다.

 


 Call by value와 Call by reference

[Call by value]

값에 의한 호출이라는 의미로 기본 데이터 타입을 매개변수로 전달할 때 사용된다.

 

참고로  이 호출 방식은 변수의 값이 복사되어 전달되므로 매개변수에 별도의 메모리 공간이 할당되어 메모리 사용량이 증가한다.

(메서드 종료 시 할당된 영역은 사라짐)

 

값에 의한 호출에서는 메서드에 파라미터로 전달되는 변수에 저장된 값의 복사본이기 때문에

메서드 내에서 매개변수의 값을 변경하더라도 호출된 쪽의 변수에는 영향을 미치지 않는다.

 

호출된 복사된 인자값은 메서드 내에서만 지역적으로 사용이되기 때문에 local value의 속성을 가져

함수 안에서 인자 값이 몇번이고 변경되더라도 외부의 변수 값은 변경되지 않는다.

 

간단한 예제를 하나 작성해봤다.

public class Main {
    public static void main(String[] args) {
        int x = 10;
        System.out.println("int x = " + x); //출력값 : int x = 10
        
        modify(x);
        System.out.println("modify x = " + x); //출력값 : modify x = 10;
    }

    public static void modify(int x) {
        x = 20;
    }
}

main메서드 내에서 int x는 10이라고 변수를 초기화 했다.

이 변수를 출력해보면 x는 여전히 10으로 출력이 된다.

 

modify메서드에서 int x를 매개변수로 받아 메서드 내 x는 20으로 값을 재할당하였다.

main메서드에서 modify메서드의 x을 호출한 후 이 값을 출력해보면 10이 출력이 될 것이다.

메서드 내에서 정의한 x를 다시 호출하면 20이 출력될 것이라고 예상할 수 있지만

실제로는 자바에서 메서드에 인자로 전달되는 변수는 값에 의한 전달이기 때문에

modify메서드 내에서 x를 변경해도 그 변경사항은 main 메서드의 로컬변수 x와는 별개의 것이다.

 

[Call by reference]

참조에 의한 호출이라는 의미로 주로 객체나 배열과 같은 참조 타입에 적용이 된다.

 

자바에서는 항상 값에의한 호출을 사용하고 엄밀히 말하면 참조에 의한 호출이라는 개념은 존재하지 않는다.

그러나 객체를 매개변수로 전달할 때는 객체의 참조값이 복사되어 전달되기 때문에 이는 매개변수가 실제 객체를

직접 가리키는 것이 아닌 객체에 대한 참조값을 가지고 있다는 의미이다.

 

그렇기 때문에 메서드 내에서 객체의 속성을 변경하면 호출한 쪽에서도 변경사항이 반영된다.

public class CallByReferenceExample {

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

        System.out.println("Before modification:");
        printArray(arr);

        modifyArray(arr);

        System.out.println("After modification:");
        printArray(arr);
    }

    // 배열을 수정하는 메서드
    public static void modifyArray(int[] array) {
        for (int i = 0; i < array.length; i++) {
            array[i] *= 2; // 각 요소를 2배로 변경
        }
    }

    // 배열을 출력하는 메서드
    public static void printArray(int[] array) {
        for (int num : array) {
            System.out.print(num + " ");
        }
        System.out.println();
    }
}

Call by reference도 예제와 함께 보면 이해가 좀 더 쉬울 것이다.

 

우선 int 타입에 크기가 5인 정수 배열을 선언하고 초기화하면 이 배열의 요소는 1, 2, 3, 4, 5로 초기화 되며,

이 배열을 수정하기 전에 출력을 해보면 배열의 요소인 1, 2, 3, 4, 5가 출력이 된다.

 

modifyArray메서드를 호출하여 배열을 수정하는데, 이 때 배열 arr이 참조로 전달된다.

modifyArray메서드 내에서 int형 기본 배열을 for문을 사용하여 각 배열의 요소를 2배로 변경하는 코드를 작성한 후

배열의 내용을 출력하면 2, 4, 6, 8, 10의 값이 출력이 된다.

 

즉 처음에는 초기화 한 값 그대로의 배열의 각 요소가 출력되지만

배열이 modifyArray 메서드로 전달되고 for문을 돌면서 각 요소가 2배로 변경되어 2, 4, 6, 8, 10이라는 값이 출력이 되는 것이다.

 

이는 메인 메서드에서 생성된 배열이 modifyArray 메서드로 전달됨에서 불구하고

수정된 배열의 내용이 메서드 외부에서도 영향을 받는 개념으로 볼 수 있다.

이미 한번 수정된 값들은 몇번을 호출, 출력하여도 그 값이 그대로 남아있게 된다.

 


면접 예상 질문과 답변

Q1. 자바에서의 함수 호출 방식의 종류?

A1. 자바에서의 함수 호출 방식에는 "Call by value"와 "Call by reference"가 있습니다.

 

Q2. 함수 호출 방식인 "Call by value"와 "Call by reference"의 각각의 차이점은?

A2. Call by value는 값에 의한 호출이라는 의미로 기본 데이터 타입을 매개변수로 전달할 때 사용되며 값이 복사되어 전달됩니다.

메서드 내에서 매개변수 값이 변경되어도 호출한 쪽 변수에는 아무런 영향을 미치지 않습니다.

Call by reference는 객체나 배열과 같은 참초 타입을 매개변수로 전달할 때 사용되며, 객체의 참조값이 복사되어 전달됩니다.

객체 주소값이 전달되기 때문에 객체의 속성을 변경하면 호출한 쪽의 객체나 배열의 값에도 변경사항이 반영됩니다.

 

Q3. 자바에서 함수 호출 시에 값에 의한 호출과 참조에 의한 호출의 사용 시기는 어떤 기준에 의해 결정하나?

A3. 두 가지 호출 방식은 전달되는 인자의 데이터 타입에 따라 결정됩니다.

 

Q4. 자바에서 Call by value와 Call by reference를 이용할 때 메모리 사용량의 차이?

A4. 값에 의한 호출은 매개변수에 별도의 메모리 공간이 할당되어 메모리 사용량이 참조에 의한 호출보다 사용량이 많습니다.

반면 참조에 의한 호출은 주소 값이 전달되므로 별도의 복사본이 생성되지 않아 메모리 사용량이 적을 수 있습니다.

 

Q5. 메모리 사용량에 대한 각각의 장단점?

A5. 값에 의한 호출은 메모리 사용량이 많지만 값이 메서드로 전달되어도 원본 데이터에 영향을 주지 않습니다.

반면 참조에 의한 호출은 메모리 사용량은 적지만 함수 내에서 데이터의 변경이 원본에 반영되어 예상치 못한 부작용이 초래될 수도 있습니다.

 

Q6. 자바에서 어느 부분이 Call by value이고, 또 어느 부분이 Call by reference에 해당되는가?

A6. 자바에서는 엄밀히 말하면 참조에 의한 호출이라는 개념은 존재하지 않습니다.

참조형의 경우 객체의 주소값을 매개변수로 전달하여 Call by reference가 아닐까하는 의문을 가질 수 있지만

정확히 말하면 주소값이 아닌 주소가 가리키는 참조값입니다.

그렇기 때문에 주소값 자체를 복사 없이 인자로 전달하는게 아닌 객체가 가지고 있는 주소값을 복사해서 전달하게 되기 때문에

기본형과 참조형 변수 모두 Call by Value에 해당합니다.


스터디를 진행하다가 Call by value와 Call by reference를 호출할 때

어떤 시점에 어떤 기준으로 호출이 결정되는지에 대한 추가 질문이 발생하였다.

 

자바에서는 무조건적으로 값에 의한 호출을 사용하고 있지만

그럼에도 어떤 시점에 어떤 호출이 결정되는지에 대한 시점을 정리해보았다.

 

1. 메서드 정의 시점

메서드를 정의할 때 매개변수의 데이터 타입에 따라 어떤 것이 호출되는지가 결정된다.

즉, 함수의 시그니처를 정의할 때 이 결정이 이루어지는 것으로 이해할 수 있다.

 

2. 메서드 호출 시점

메서드가 호출될 때 전달되는 인자의 데이터 타입에 따라 결정이 된다.

메서드 호출 시 메서드에 전달되는 값 또는 객체의 데이터 타입을 기준삼는다.

 

정리를 해보자면 메서드가 정의 될 때 매개변수의 타입이 결정되고, 메서드를 호출할 때 전달되는 인자의 타입에 따라서결정된다고 볼 수 있다. 이는 컴파일 할 때 결정되고 런타임 시점에는 이미 결정된 호출 방식을 따르게 된다.