결론: 자바는 call by value입니다
=> Call by reference는 원본의 주소값을 전달하므로, 원본을 변경할 수 있습니다. 왜냐하면 주소값을 통해 원본에 접근할 수 있기 때문입니다.
자바에는 포인터 같은 변수의 주소값을 추출 및 저장하는 기능이 없습니다. 그렇기에 call by reference가 될 수 없습니다.
(아래 글은 참조에 관해 이해를 하시고 나서 보는 걸 추천드립니다.)
2021.03.24 - [gyub's 공부일기/Java] - [ JAVA ] 참조란?
Call By Value ( 값에 의한 호출 )
Call By Value는 원본 값을 그대로 복사하여 매개변수로 전달하는 것입니다.
public class JavaIsCallByValue {
public static void main(String[] args) {
int a = 1;
int b = 3;
System.out.println("swap 전 a:" + a + " " + "b:" + b);
swap(a, b);
System.out.println("swap 후 a:" + a + " " + "b:" + b);
}
private static void swap(int x, int y) {
int tmp = x;
x = y;
y = tmp;
}
}
위에서의 출력 결과는 어떻게 될까요?
swap메서드를 호출 했음에도 값이 전혀 바뀌지 않았죠.
왜 이러는 것일까요??
위의 그림에서 보이듯이 x와 y 그리고 a 와 b는 서로 다른 메모리 주소를 갖고있습니다.
그러므로 실제 a와 b의 값이 변경되는 것이 아닌 x와 y의 값만 변경되는 것이죠
좀 더 자세히 말하자면 a와 b를 매개변수로 swap메서드를 호출 했을 때, a와 b의 값이 복사되어져 x와 y에 값에 들어가있고 이 복사된 값들을 이용해 x와 y의 값을 변경한 것 뿐입니다.
그러니 원본인 a와 b의 값은 변경될 리 없죠.
이번엔 primitive type이 아닌 reference type으로 다시볼게요.
public class JavaIsCallByValue {
public static void main(String[] args) {
Num numA = new Num(1);
Num numB = new Num(3);
System.out.println("swap 전 numA:" + numA.num + " " + "numB:" + numB.num);
swap(numA, numB);
System.out.println("swap 후 numA:" + numA.num + " " + "numB:" + numB.num);
}
private static void swap(Num numX, Num numY) {
Num tmp = numX;
numX = numY;
numY = tmp;
}
public static class Num {
int num;
public Num(int num) {
this.num = num;
}
}
}
위의 출력결과는 어떻게 될까요?
변함이없습니다.
만약 call by reference였다면 둘의 값이 변경되어야 하는 것이 맞는거죠.
좀 더 자세히 설명하자면 위의 코드는 Num이라는 클래스를 선언하고 각각 1과 3의 필드값(num)을 가진 인스턴스를 생성했어요.
그 후 swap메서드를 통해 두 개의 참조를 바꿨죠. 하지만 둘의 필드값은 변하지 않았어요. 자바가 call by reference였다면 이 둘의 참조도 바뀌며 값도 함께 변경이 됐어야 하는것입니다.
하지만 자바가 call by value냐 call by reference에 대한 의견이 갈리는 것은 아래의 예제 때문인데요.
public class JavaIsCallByValue {
public static void main(String[] args) {
Num numA = new Num(1);
Num numB = new Num(3);
System.out.println("swap 전 numA:" + numA.num + " " + "numB:" + numB.num);
swap(numA, numB);
System.out.println("swap 후 numA:" + numA.num + " " + "numB:" + numB.num);
}
private static void swap(Num numX, Num numY) {
int tmp = numX.num;
numX.num = numY.num;
numY.num = tmp;
}
public static class Num {
int num;
public Num(int num) {
this.num = num;
}
}
}
위의 출력 결과는
이렇게 필드값이 변경되었습니다. 그렇다면 이건 왜 그러는걸까요?
자바가 call by reference가 아닌 이유가 필드값이 변경이 안 됐기 때문이라고 한 것 같은데..
이런 예외적인 경우는 자바가 함수의 인자로 전달해주는 것은 복사된 참조 값을 전달하기 때문인데요.
즉, 참조값을 받아서 그 참조값을 이용하는 것은 가능하기에 각각의 필드값이 변경되는 것입니다.
긴 글 읽어주셔서 감사합니다.
'gyub's 공부일기 > Java' 카테고리의 다른 글
[ JAVA ] 참조란? (3) | 2021.03.24 |
---|---|
[JAVA] JVM 클래스로더 (0) | 2020.12.10 |
[ JAVA ] JAVA의 동작 방식와 JVM 메모리 구조 (0) | 2020.11.30 |
[ JAVA ] Java의 특징 및 JVM, JDK, JRE (0) | 2020.11.29 |