Java의 배열이 "Call by Value"를 위반합니까?
“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);
}
}
출력은
n
의 main()
가 변경되지 않은 상태로 유지됨을 보여줍니다.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는 항상 값에 의한 호출입니다.
Reference
이 문제에 관하여(Java의 배열이 "Call by Value"를 위반합니까?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/jdeisenberg/do-arrays-in-java-violate-call-by-value-1fb5텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)