자바는 call by value 만 존재한다
* 학습내용을 정리한 것으로 아래 내용이 꼭 정답을 의미하진 않습니다.
1. call by refernece 인가 call by value 인가?
자바에 대해 공부를 막 시작할 무렵 " 자바는 call by value 로만 동작한다 " 는 문장을 어렴풋이 듣고만 넘어갔었다. 그래서 그냥 " 아 자바는 C 처럼 call by value 로 동작하는구나 " 라고 생각하고 그냥 그런줄로 알고 있었다. 그런데 최근 자료구조와 자바 문법을 되돌아보며 여러 인터넷 글을 돌아보던 중 Java가 call by reference로 동작하는지 여부에 대해 논하는 글을 보게되었다.그 글을 본 뒤로 정확한 이유를 알지 못하고 넘어갔던 문제를 다시 한번 짚고 넘어가자는 생각으로 관련 정보를 찾아보았다.
토비의 스프링 저자이신 토비님께서 이와 관련해 글을 쓰신적이 있었다.
위 글을 요약하자면 결국 "자바는 call by value로 동작한다" 이다.
위에서 언급된 영문을 해석하면 ...
"pass by reference라는 용어는 정확히말하면, argument가 함수로 전달될 때 호출된 함수는 값의 복사본이 아니라 원래 값에 대한 참조를 얻는다. 만약 함수가 parameter를 수정하면, 호출하는 코드의 값은 바뀔것이다. argument(원래 변수) 와 parameter(함수 정의에서의 변수) 는 같은 메모리 공간을 사용하기 때문이다. ... (생략) 자바는 객체를 레퍼런스에 의해 전달하지 않는다. 자바는 객체의 레퍼런스(포인터)를 값으로 전달한다."
나는 call by reference가 C에서 포인터(주소 값)을 인자로 넘겨주고 함수 내에서 역참조로 해당 포인터가 가리키는 값을 변경해주는 것이라고 생각했다. 근데 이건 위에서 포인터를 전달한다는 것과 같은 의미아닌가? 그렇다면 내가 알고있던 call by reference가 좀 다른 의미라고 봐야한다. 엄밀히 말하면 call by address 지만 call by reference 와 구분짓지 않고 다들 이야기하길래 그냥 그렇게 같은 것인줄 알았다. 하지만 위 토비님 글에서 "C에도 call by reference가 있다는 식의 이야기와 비슷하다" 는 말의 뉘앙스를 보아도 C 에는 call by reference 가 없다는 말처럼 들린다. 그래서 좀 더 자세히 찾아보기로 했다.
참으로 여러가지 이야기가 있고 역시나 call by address 와 call by reference를 같은 의미로 사용하는 글이 많았다. 국내와 국외를 가리지 않고 그랬다. 그래서 뭐가 맞는 말인지 참 어려웠는데 "왠지 이걸 말하는건가?" 싶은 글이 하나 있었다.
"There is no concept of variable reference in C, as there is in C++. What you show in your small example is simply a use of a pointer (or variable address). But you are passing a value (the address of the variable) not a reference (an alias of the variable name)."
https://stackoverflow.com/questions/59048556/no-call-by-reference-in-c
No Call by reference in C?
I know, the title is a little bit odd. Of course I know how to do call-by-reference in C. My problem is simple and the solution could be simple as well. I am currently going through some scripts of...
stackoverflow.com
"C에는 C++ 처럼 변수 reference 개념이 없다."
즉 C++ 의 call by reference와 C의 call by reference는 다르다. 하지만 대부분 이를 혼용해서 사용하고 있고 이 부분에서 혼란이 발생하는 것 같았다. C++ 에서 reference 는 원본 변수의 별명(alias)과 같다. 아래는 포인터와 레퍼런스의 차이다.
// 포인터와 원본 주소는 같지만 포인터 변수의 주소와는 다르다
ptr == &num
&ptr != &num
// 참조자는 원본과 모든 것이 같다
ref == num
&ref == &num
위 이야기를 종합해보면 사람들이 call by address 와 call by reference를 혼용해서 사용했고 자바도 같은 이유로 오해했다.. 정도로 보인다. 그럼 왜 자바가 call by address 가 아니라 call by value를 사용한다고 하느냐고 묻는다면 그냥 용어의 차이같다. call by value가 value 복사본을 전달해주듯 call by address 도 포인터(주소값)을 복사해서 넘겨준다. 넘겨주는게 실제 값이냐 주소 값이냐의 차이다.
내 결론 :
1. Java는 call by value 로 동작한다.
2. call by value : argument 값을 복사해서 parameter로 전달
3. call by address : call by value와 같으나 포인터(address)를 parameter로 전달
4. call by reference : C++ 에서 사용하는 reference(참조자, 원본 변수의 별명)를 전달
2. 번외 : 포인터와 참조자는 다른가?
이 주제에 대해 길게 쓸건 아니고 위 내용을 찾다가 글을 하나 찾게되었다.
https://woo-dev.tistory.com/43
[C++] 포인터와 레퍼런스(참조)의 차이를 이해해보자
C++에는 포인터(Pointer)와 레퍼런스(Reference)라는 개념이 있다. 포인터는 C 에도 있었던 개념이며 레퍼런스는 C++ 에서 등장한 개념이다. 언뜻 보면 용도가 비슷한데 정확히 어떤 차이점이 있는지,
woo-dev.tistory.com
위 블로그 주인분이 쓰신 글을 보면 내부적으로 동작할 때는 같은 과정을 거치는 것으로 보인다.
인자를 파라미터로 받아올 때 레지스터로 받아온 주소값을 메모리에 저장하는 똑같은 과정을 거친다.
그럼 뭐가 다른건가 생각했을 때, 메모리에 저장한 주소값을 복사해서 사용할 것인가 그대로 사용할 것인가.. 그 차이같다.
아래는 내가 확인해본 테스트 결과다.
ptr은 변수 주소가 다르지만 ref와 num 은 완전히 같다. 별명만 다르게 붙여준 같은 변수다.
3. 번외 : Integer 는 왜 원본 값이 안바뀌지?
자바는 reference type 변수의 주소값을 매개변수로 전달받는다. 즉 메소드 내에서 원본 값을 변경할 수 있다.
위 내용을 원래 알고있었다. 그래서 실험을 하나 했는데 int 변수와 Integer 변수 중에 Integer 변수는 기본타입이 아닌 인스턴스니까 값이 변하나? 라는 의문을 풀기 위한 것이었다.
결론은 안바뀐다. 알고보니 Integer은 Immutable 이었다. 그럼 새로운 인스턴스를 담아주면 바뀌나?
이것도 안바뀐다. 이건 아래 링크에 설명되어있다.
https://stackoverflow.com/a/12429953/5013556
Is Java "pass-by-reference" or "pass-by-value"?
I always thought Java uses pass-by-reference. However, I read a blog post which claims that Java uses pass-by-value. I don't think I understand the distinction the author is making. What is the
stackoverflow.com
main 메소드의 b와 test 메소드의 b는 다른 변수다. test가 호출되면 비어있는 변수 b가 새롭게 생기고 포인터로 전달된 main 메소드의 인스턴스 b 를 가리킨다. 이 상태에서 새로운 Integer 인스턴스 c 를 만들고 변수 b에 대입하면 main 메소드의 b 변수가 새로운 c 인스턴스를 가리키는게 아니다. test 메소드의 b 변수가 c 인스턴스를 가리키게된다.
이 같은 Immutable Class 는 String, Boolean, Integer, Float, Long, Double (Wrapper Class) 등이 있다.