CodeGym /행동 /JAVA 25 SELF /값에 의한 전달과 참조에 의한 전달

값에 의한 전달과 참조에 의한 전달

JAVA 25 SELF
레벨 8 , 레슨 4
사용 가능

1. 소개

여러 프로그래밍 언어에는 함수(또는 메서드)에 매개변수를 전달하는 두 가지 기본 방식이 있습니다:

  • 값에 의한 전달: 함수는 변수 값의 복사본을 받습니다. 함수가 매개변수를 변경해도 원본은 바뀌지 않습니다.
  • 참조에 의한 전달: 함수는 원본 객체에 대한 “참조”(포인터)를 받습니다. 함수 내부의 변경이 원본에 반영됩니다.

Java에서는 모든 매개변수가 값에 의해서만 전달됩니다!
하지만 여기엔 함정이 있습니다. 원시 타입(int, double, boolean 등)을 전달할 때는 값 자체가 복사됩니다. 반면 참조 타입(예: 배열이나 객체)을 전달할 때는 참조의 값(즉, 메모리에서 객체의 “주소”)이 복사될 뿐, 객체 자체는 복사되지 않습니다.

머리가 복잡해지기 시작해도 걱정하지 마세요 — 지금부터 차근차근 정리하고 예제로 보여 드리겠습니다!

2. 원시 타입: 값이 복사됩니다

간단한 것부터 시작해 봅시다. 메서드 안에서 int 타입 변수의 값을 바꾸려고 하면 무슨 일이 일어날까요?

public class Demo 
{
    public static void main(String[] args) 
    {
        int number = 5;
        changeValue(number);
        System.out.println(number); // 무엇이 출력될까요?
    }

    public static void changeValue(int n) 
    {
        n = 42;
    }
}

결과: 화면에 5가 출력됩니다.

왜 그런가요?
메서드 changeValue에는 변수 number의 값 복사본이 전달됩니다. 메서드 내부에서는 복사본(n)만 바뀌며, main의 원본 변수 number는 그대로입니다.

비유
비유하자면, 원본이 아니라 여권의 복사본을 친구에게 건넨 것과 같습니다. 친구가 복사본에 수염을 얼마든지 그려도 — 당신의 진짜 여권은 그대로입니다!

3. 참조 타입: 참조가 복사됩니다

이제 배열로 같은 실험을 해 보겠습니다:

public class Demo 
{
    public static void main(String[] args) 
    {
        int[] numbers = {1, 2, 3};
        changeFirst(numbers);
        System.out.println(numbers[0]); // 무엇이 출력될까요?
    }

    public static void changeFirst(int[] arr) 
    {
        arr[0] = 99;
    }
}

결과: 화면에 99가 출력됩니다.

왜 그런가요?
메서드 changeFirst에는 배열 numbers에 대한 참조의 복사본이 전달됩니다. 두 이름(mainnumbers와 메서드의 arr)은 메모리에서 같은 배열을 가리킵니다. 따라서 메서드 안에서 배열의 요소를 바꾸면, 그 변경이 바깥에서도 보입니다.

시각화

main: numbers ──► [1, 2, 3]
                   ▲
                   │
changeFirst: arr ──┘
참조의 복사본은 메모리에서 같은 객체를 가리킵니다

arr[0]을 변경하면 실제로 numbers[0]이 바뀝니다. 둘 다 동일한 객체를 가리키기 때문입니다.

4. 하지만 참조 자체를 바꾸면 — 원래 객체는 변하지 않습니다!

이번엔 이렇게 해 봅시다:

public class Demo 
{
    public static void main(String[] args) 
    {
        int[] numbers = {1, 2, 3};
        replaceArray(numbers);
        System.out.println(numbers[0]); // 무엇이 출력될까요?
    }

    public static void replaceArray(int[] arr) 
    {
        arr = new int[] {10, 20, 30};
    }
}

결과: 1을 출력합니다.

왜 그런가요?
메서드 replaceArray에서 변수 arr는 새로운 배열을 가리키게 되지만, 이는 main의 변수 numbers에는 아무 영향도 주지 않습니다.
두 변수는 같은 참조를 공유하고 있었지만, 메서드 내부에서 arr = ...를 수행하면 그것은 오직 로컬 변경일 뿐입니다.

비유
이는 당신과 친구가 같은 집 열쇠를 하나씩 갖고 있던 상황과 같습니다. 친구가 새 열쇠를 만들어도 당신의 예전 열쇠는 그대로이고, 문도 그대로입니다.

5. 개념 확인: 메서드로 두 int를 “서로 바꾸기”는 불가능

많은 초보자가 두 수를 서로 바꾸는 메서드를 작성하려고 하지만, 제대로 작동하지 않습니다:

public class Demo 
{
    public static void main(String[] args) 
    {
        int a = 5, b = 10;
        swap(a, b);
        System.out.println(a + " " + b); // 예상: 10 5, 실제로는?
    }

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

결과: 화면에 5 10이 출력됩니다.

왜일까요?
swap에는 변수 ab의 복사본이 전달됩니다. swap 내부에서 하는 모든 작업은 이 복사본들에만 영향을 주며, 원본에는 영향을 주지 않습니다.

6. 하지만 배열은 내용물을 바꿀 수 있습니다!

배열에서 값을 서로 바꾸는 올바른 방법을 보겠습니다:

public class Demo 
{
    public static void main(String[] args) 
    {
        int[] arr = {5, 10};
        swap(arr);
        System.out.println(arr[0] + " " + arr[1]); // 예상: 10 5
    }

    public static void swap(int[] arr) 
    {
        int temp = arr[0];
        arr[0] = arr[1];
        arr[1] = temp;
    }
}

결과: 10 5를 출력합니다.

왜 그런가요?
원본 변수와 메서드 매개변수 모두가 가리키는 객체(배열)의 내용물을 변경하기 때문입니다.

7. 데모: 객체와 그 필드

배열은 이해했습니다. 그럼 우리가 정의한 클래스의 객체는 어떨까요? 완전히 동일합니다!

class Box 
{
    int value;
}

public class Demo
{
    public static void main(String[] args) 
    {
        Box box = new Box();
        box.value = 7;
        changeBox(box);
        System.out.println(box.value); // 무엇이 출력될까요?
    }

    public static void changeBox(Box b) 
    {
        b.value = 42;
    }
}

결과: 42를 출력합니다.

왜 그런가요?
참조가 가리키는 객체의 필드를 변경하고 있기 때문입니다.

메서드로 매개변수를 전달할 때 무슨 일이 일어나는가

무엇을 전달하는가 어떻게 복사되는가 메서드 안에서 변경 가능? 바깥에서 변경이 보이나?
int, double 값의 복사본 가능, 하지만 복사본만 아니오
배열 참조의 복사본 가능, 요소를 변경하는 경우
객체(클래스) 참조의 복사본 가능, 필드를 변경하는 경우
배열/객체 참조의 복사본 불가, 새 참조를 할당하는 경우 아니오

8. 흔한 실수

오류 № 1: 메서드 호출 후 int가 바뀔 것이라고 기대함. 많은 초보자가 int 변수를 메서드에 넘기면 메서드 내부에서 그 값을 바꿀 수 있다고 생각합니다. 이는 잘못입니다. 바뀌는 것은 오직 복사본뿐입니다!

오류 № 2: 메서드로 두 int를 서로 바꾸려 함. 이미 보았듯이 이는 불가능합니다 — 서로 바뀌는 것은 변수의 복사본뿐이며, 원본은 영향을 받지 않습니다.

오류 № 3: 메서드로 배열을 “교체”하려 함. 메서드 안에서 매개변수-배열에 새 배열(arr = new int[]{...})을 할당해도 원본 배열에는 영향을 주지 않습니다. 배열을 “교체”하려면 — 메서드에서 새 배열을 반환하고 호출하는 코드의 변수에 그것을 할당해야 합니다.

오류 № 4: 객체의 내용물을 바꿀 수 있다는 사실을 잊음. 객체(또는 배열)를 전달한다면, 그 필드/요소의 변경은 바깥에서도 보인다는 점을 잊지 마세요!

오류 № 5: null과의 혼동. null인 참조를 메서드에 전달하고 그 필드에 접근하려고 하면 NullPointerException이 발생합니다. 주의하세요!

1
과제
JAVA 25 SELF, 레벨 8, 레슨 4
잠금
로봇 궤적의 시작점 재설정 🤖
로봇 궤적의 시작점 재설정 🤖
1
과제
JAVA 25 SELF, 레벨 8, 레슨 4
잠금
플레이어 보너스 목록을 교체하려는 시도 🎁
플레이어 보너스 목록을 교체하려는 시도 🎁
1
과제
JAVA 25 SELF, 레벨 8, 레슨 4
잠금
축구팀에서 선수 위치 바꾸기 ⚽
축구팀에서 선수 위치 바꾸기 ⚽
1
과제
JAVA 25 SELF, 레벨 8, 레슨 4
잠금
마법 상자 내용 업데이트 📦
마법 상자 내용 업데이트 📦
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION