Java의 배열이 "Call by Value"를 위반합니까?

16358 단어 javaarraysmethods

“Any headline that ends in a question mark can be answered by the word ‘no’.”
-- Betteridge’s Law of Headlines



Java의 메서드에 대해 처음 배웠을 때 "인수는 항상 값에 의해 매개 변수에 전달됩니다."와 같은 내용을 읽었을 것입니다. 이는 매개변수가 항상 인수의 사본임을 의미합니다. 원하는 모든 매개변수 값을 변경할 수 있으며 원래 인수는 영향을 받지 않습니다. 이 코드에서:

public class ByValue1 {
    public static void printCube(int n) {
        n = n * n * n;
        System.out.println("The cube is " + n);
    }

    public static void main(String[] args) {
        int n = 12;
        System.out.println("Before call, n is " + n);
        printCube(n);
        System.out.println("After call, n is " + n);
    }
}


출력은 nmain()가 변경되지 않은 상태로 유지됨을 보여줍니다.

Before call, n is 12
The cube is 1728
After call, n is 12


이것은 좋은 일입니다. printCube(3);를 호출한다고 상상해 보십시오. Java가 리터럴 3을 27로 변경하는 것을 원하지 않을 것입니다!

더 나아가 Java를 사용하는 동안 배열을 접했고 다음과 같은 프로그램을 보았을 것입니다.

import java.util.Arrays;

public class ByValue2 {
    public static void cubeArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr[i] * arr[i] * arr[i];
        }
    }

    public static void main(String[] args) {
        int [] data = {10, 2, 4};
        System.out.println("Before call, data is " +
           Arrays.toString(data));
        cubeArray(data);
        System.out.println("After call, data is " +
            Arrays.toString(data));
    }
}


이 프로그램을 실행하면 다음과 같은 결과가 나타납니다.

Before call, data is [10, 2, 4]
After call, data is [1000, 8, 64]


무슨 일이야? 배열 내용이 변경되었습니다! 이것이 "값에 의한 항상 호출"에 대한 예외입니까? 아니요, 그렇지 않습니다. 여기서 핵심은 배열이 참조라는 것입니다. 다음은 cubeArray 메서드를 입력할 때 메모리 다이어그램의 모습입니다.



곱셈arr[i] * arr[i] * arr[i]을 수행할 때 Java는 i가 참조하는 메모리에서 요소arr를 변경합니다. 자체적으로 변경되지 않습니다arr. 배열의 메모리 주소를 표시하는 참조를 인쇄하여 이를 증명할 수 있습니다.

import java.util.Arrays;

public class ByValue3 {
    public static void cubeArray(int[] arr) {
        System.out.println("At start of cubeArray, arr is "
            + arr);
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr[i] * arr[i] * arr[i];
        }
        System.out.println("At end of cubeArray, arr is "
            + arr);
    }

    public static void main(String[] args) {
        int [] data = {10, 2, 4};
        System.out.println("Before call, data is " +
            Arrays.toString(data) + " reference " + data);
        cubeArray(data);
        System.out.println("After call, data is " +
            Arrays.toString(data) + " reference " + data);
    }
}

System.out.println 를 사용하여 배열을 인쇄하면 [I@764c12b6 와 같은 것을 얻을 수 있습니다. 즉, 메모리 위치 764c12b6([)에 정수(I)의 배열(@764c12b6)이 있음을 의미합니다. 프로그램을 실행하면 참조가 변경되지 않았음을 알 수 있지만 참조된 배열은 다음과 같습니다.

Before call, data is [10, 2, 4] reference [I@764c12b6
At start of cubeArray, arr is [I@764c12b6
At end of cubeArray, arr is [I@764c12b6
After call, data is [1000, 8, 64] reference [I@764c12b6


따라서 실제로 이 프로그램은 값에 의한 호출 문제를 어떤 식으로든 해결하지 않습니다. 여기서는 참조arr 자체를 변경한 것이 없기 때문입니다. 새로운 어레이를 참조하도록 설정하겠습니다arr.

public class ByValue4 {
    public static void cubeArray(int[] arr) {
        System.out.println("At start of cubeArray, arr is "
            + arr);
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr[i] * arr[i] * arr[i];
        }
        // make arr refer to a different area of memory
        arr = new int[4]; 
        System.out.println("At end of cubeArray, arr is "
            + arr);
    }

    public static void main(String[] args) {
        int [] data = {10, 2, 4};
        System.out.println("Before call, data is " +
            Arrays.toString(data) + " reference " + data);
        cubeArray(data);
        System.out.println("After call, data is " +
            Arrays.toString(data) + " reference " + data);
    }
}


다음은 떠나기 직전의 메모리 다이어그램입니다arr.



값에 의한 호출이 실제로 모든 곳에서 작동하는 경우 cubeArray()data에 대한 참조가 변경되지 않아야 합니다. 출력을 보자:

Before call, data is [10, 2, 4] reference [I@764c12b6
At start of cubeArray, arr is [I@764c12b6
At end of cubeArray, arr is [I@4e0e2f2a
After call, data is [1000, 8, 64] reference [I@764c12b6


출력의 세 번째 줄은 main() 메서드에서 arr 참조(매개 변수)를 변경했지만 네 번째 줄은 cubeArray()의 원래 data 참조가 영향을 받지 않았음을 보여줍니다. 참조는 실제로 값으로 전달됩니다.

따라서 기사 헤드라인에 대한 답변: Do Arrays in Java Violate "Call by Value"? 대답은 "아니오"입니다. Java는 항상 값에 의한 호출입니다.

좋은 웹페이지 즐겨찾기