본문 바로가기

Java는 Call by Value? Call by Reference?

얼마 전에 같이 공부하는 형이 갑자기 물어봤다.

자바는 call by value와 call by reference중 어떤 게 맞을까?

그 때 형이 내린 결론은

'자바는 call by value지만 이걸 굳이 나누는 것은 무의미한 거 같다. 이것은 C언어의 잔재다.' 이었다.



하지만 오늘 자바의신을 읽는데 책에 또 이 부분이 언급됐었다. (책에서는 call대신 pass로 표기했는데 똑같은 의미다)

책에서는 이렇게 말한다.

- 모든 기본 자료형은 pass by value

- 참조 자료형은 값이 아닌 참조가 전달되는 Pass by Reference


난 그래서 여기서 또 혼란이 왔다. 내가 잘못 알고 있는건가? 그래서 다시 한번 알아봤고

나같이 혼란스러워하는 사람들이 많아서 해답을 찾기는 쉬웠다.



질문: 자바는 "pass by reference"인가 "pass by value"인가?

출처 : https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value


가장 추천 수가 많았던 댓글에서는 이렇게 말한다.


자바는 항상 pass by value다.

불행하게도, 객체를 전달할 때 Reference를 전달하는데 이것은 초보자들을 헷갈리게 한다.


이런 식으로 :

public static void main(String[] args) {
   Dog aDog = new Dog("Max");
   Dog oldDog = aDog;

   // we pass the object to foo
   foo(aDog);
   // aDog variable is still pointing to the "Max" dog when foo(...) returns
   aDog.getName().equals("Max"); // true
   aDog.getName().equals("Fifi"); // false
   aDog == oldDog; // true
}

public static void foo(Dog d) {
   d.getName().equals("Max"); // true
   // change d inside of foo() to point to a new Dog instance "Fifi"
   d = new Dog("Fifi");
   d.getName().equals("Fifi"); // true
}

위의 예에서 aDog.getName() 은 여전히 "Max"를 return한다.

객체 참조가 value에 의해 전달 된 것처럼 main의 aDogfoo 함수의 Dog "Fifi"와 함께 변경되지 않는다.

reference로 전달 된다면, foo를 호출 한 후 main에 있는 aDog.getName()"Fifi"를 반환 했을 것이다.


이렇게:

public static void main(String[] args) {
   Dog aDog = new Dog("Max");
   Dog oldDog = aDog;

   foo(aDog);
   // when foo(...) returns, the name of the dog has been changed to "Fifi"
   aDog.getName().equals("Fifi"); // true
   // but it is still the same dog:
   aDog == oldDog; // true
}

public static void foo(Dog d) {
   d.getName().equals("Max"); // true
   // this changes the name of d to be "Fifi"
   d.setName("Fifi");
}

위의 예에서, foo(aDog) 를 호출한 후에aDog.getName()은 Fifi 가 된다.

왜냐하면 객체의 이름은 foo 내부에서 setName('Fifi') 되었기 때문이다.

food에서 수행하는 모든 연산은 모든 실질적인 목적을 위해 aDog에서 수행되지만, 변수 aDog 자체의 값을 변경할 수는 없다.


요약하자면

call by value로 전달된 것처럼 foo 내부에서의 변경(new Dog("Fifi"))는 적용되지 않는다.

하지만 setter 메소드를 이용한 aDog필드의 값은 변경이 가능하다. 이 때문에 사람들이 헷갈려한다.

즉 aDog 자체 reference를 바꾸는 것은 불가능하지만 setter 메소드를 이용한 aDog필드의 값은 변경이 가능하다.



그리고 또 하나의 추천이 많은 댓글에서는 이렇게 말한다.

이 문제의 혼란 대부분은 다른 사람들이 "reference"라는 용어에 대한 다른 정의를 가지고 있다고 생각한다. C에서 온 사람들은 "reference"는 "pointer"와 같다. C++에서 온 사람들은 C++에서의 의미와 같다. Java reference가 실제로 전달되는 것이 올바른지 여부는 "reference"가 의미하는 바에 달려 있다.


결론

reference를 어떻게 정의하냐에 따라서 다르기 때문에 사람마다 다른 답을 가지고 있지만

나는 형이 말했던

'자바는 call by value지만 이걸 굳이 나누는 것은 무의미한 거 같다. 이것은 C언어의 잔재다.' 라고 생각한다.