자바는 Pass By Value인가? Pass By Reference인가? 에 대해서 검색을 계속 진행 해보았다. 자바를 처음 만든 개발자의 얘기 부터, StackOverFlow에서의 열띤 토론 등을 바라보며, 내 생각을 글로 작성해 보는 게 좋겠다는 생각이 들었다😀
우선 Pass By의 뜻은 뭘까?🤔
자료들을 참조했을 때 Parameter 전달 방식
으로 해석했을 때, 딱 들어 맞았던 것 같다.
즉, Method를 호출했을 때, Parameter를 어떤 방식으로 전달하냐는 뜻이었다.
Value로 Parameter를 전달하는지, 아니면 Reference로 Parameter를 전달하는지.
여기서 Pass By Value란, 함수의 Parameter로 변수를 전달하는 방법 중 값을 복사해서 전달하는 방식
이다. 여기서 복사!
이 단어가 핵심이다.
그리고 Pass By Reference란, 변수의 주소를 전달하는 방식
이다. 복사가 아닌! 주소 자체를 전달하는 방식
이다.
Java는 Pass By Value
이다.
From the authors of Java: "There is exactly one parameter passing mode in Java - pass by value - and that helps keep things simple." The Java Programming Language, 2nd ed. by Ken Arnold and James Gosling, section 2.6.1, page 40, 3rd paragraph.
Java를 최초로 개발한 James Gosling
이 정확히 Pass By Value
라고 언급했었다.
그런데 엄청나게 다양한 의견들이 난무했다.🤔
Primitive Type에 대한 의견은 통일되었지만, Reference Type에 대해서는 Pass By Value Or Reference인지 의견이 다양했다.
https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value
나 역시 Referece Type에 대한 부분에서 혼동이 왔었고 내가 이해한 부분에 대해서 밑에 적어 보려고 한다.
Java에서는 main Method를 호출 시 호출 하기 직전에 각 Method마다 JVM Stack에 Frame을 생성하고 실행이 완료된 Method는 JVM Stack에서 사라진다. 해당 Frame내부에는 Local Variables
가 존재하고 Parameter값 부터 0번 부터 순차적으로 Local Variables에 들어가게 된다. 이 때, Parameter 값들은 전부 복사가 되어서 들어가진다. Primitive Type은 값이, Reference Type은 참조값이 복사 되어서 들어간다.
아래의 코드를 보자🕵️
class Person {
private int age;
public int getAge() {
return age;
}
public Person(int age) {
this.age = age;
}
}
public class Main {
private static void updateReferenceType(Person person) {
person = new Person(20);
}
public static void main(String[] args) {
Person referenceTypePerson = new Person(29);
// output: before update reference type: 29
System.out.println("before update reference type: " + referenceTypePerson.getAge());
updateReferenceType(referenceTypePerson);
// output: after update reference type: 29
System.out.println("after update reference type: " + referenceTypePerson.getAge());
}
}
처음 main Mathod가 호출되기 직전에, JVM Stack에 Main-Frame이 생성이 되고, 호출 시, Heap영역에 Person 객체가 생기고, referenceTypePerson이 해당 객체를 참조하게 된다.
updateReferenceType Method가 호출 되면 local Variables가 구성되고 0x1234에 해당 참조값의 복사본이 0번 인덱스로 들어가지고 같은 Person 객체를 가리키게 된다.
updateReferenceType Method 내부에 new Person(20) 생성자를 통해 생성한다면 Heap영역에 새로운 객체가 생성되고 가리키는 참조값은 0x2345로 변경이 된다.
updateReferenceType Method가 종료되면 Stack에서 사라지게 되며,
Heap 영역에 0x2345 주소를 가진 Person 객체는 GC의 수거 대상이 된다.
여기서의 핵심은 local Variables에 생성된 값(참조값)은 복사가 되어져 전달이 된다는 것이다. updateReferenceType Method의 Parameter인 Person의 참조값 0x1234는 복사가 되어져 local Variables[0] Index에 값으로 들어가지게 되었다.
위에서 정의한 Pass By Value에 대해서 다시 한 번 적어보면,
Pass By Value란, 함수의 Parameter로 변수를 전달하는 방법 중 값을 복사해서 전달하는 방식
이다.