기본 콘텐츠로 건너뛰기

[JAVA] pass-by-value & pass-by-reference

pass-by-value? or pass-by-reference? in JAVA

JAVA 개발을 8년째 해오고 있지만, 아직도 기본이 부족하다고 느낄때가 참 많습니다.
최근에는 대학교 1학년 학부 생활할때쯤 배웠던 
'pass-by-value (call-by-value)' / 'pass-by-reference (call-by-reference)'에 대해서 다시 한번 개념을 정리한 계기가 있었습니다.

먼저 퀴즈를 통해 접근해 보도록 하죠.

퀴즈) 다음과 같은 코드에서 출력되는 count값은?
@Test
public void passByValueTest() {
   Integer count = 1;
   increment(count);
   System.out.println("* count : " + count);
}
private void increment(Integer count) {
   count++;
   ++count;
}
아마도 대부분의 사람들이 "3"이라고 대답하지 않을까 싶습니다.
또는 증가 연산자인 '++' 의 위치에 대해서 뭔가 함정이 있을까 고민할수도 있겠네요.

누군가는 당연하다고 여길지 모르겠으나 정답은 "1" 입니다. 


즉, count값은 변경되지 않습니다. 
(정확하게 얘기하면 passByValueTest() 메소드안의 count값이 변경되지 않습니다.)
JAVA만 공부하셨던 분들은 당연하게 받아들이시는 분들도 있으실테지만,
C나 여타 다른 언어를 함께 공부하셨던 분들은 약간 혼란스러운 부분이 있을수 있을것 같습니다. (JAVA에서 object를 넘기면 pass-by-reference 아닌가?? JAVA에선 reference를 어떻게 넘기지?)
JAVA엔 포인터를 안쪽에 숨기고 있기 때문에 이런 혼란스러움이 생기는것 같은데요,
JAVA는 오직 pass-by-value만 사용된다고 생각하시면 됩니다.
즉, Only 값만 전달해 주게 됩니다. ('값은 동일하고 해당 값의 포인터를 갖는 레퍼런스는 다르다'라는 개념으로 보시면 됩니다. 말이 좀 어렵긴하쥬?)

그림으로 표현하면 다음과 같습니다.


위 그림을 보시면 아시겠지만 'increment()'안에 있는 'count' 변수는 'passByValueTest()'안에 있는 count변수에 아무런 영향도 주지 않습니다. (직접 메모리 주소값을 찍어보며 테스트한 결과 입니다.)
이 그림을 'pass-by-value'의 케이스로 보시면 됩니다. (반대로 pass-by-reference는 어떻게 될지 대충 예상이 되시죠?)
오해하실까봐 말씀드리지만 primitive타입 관계 없이 Integer와 int 모두 동일하고 일반 Object또한 모두 동일하게 처리됩니다. 
추가로 JAVA로 swap 메소드를 만들어 보시면 딱! 감을 잡으실 수 있으리라 생각이 드네요.

[참고 링크]
   : 위 링크를 보시면 단계별로 그림과 함께 잘 설명되어 있습니다.
   : stackoverflow에서 엄청 HOT! 했던 이슈 입니다.
   : stackoverflow 이슈를 잘 정리한 내용입니다.

댓글

이 블로그의 인기 게시물

HATEOAS(Hypermedia As The Engine of Application State) HATEOAS란? - REST application 의 규약 - 클라이언트는 선행정보 없이 서버로부터 전송되는 데이터만으로도 인터렉션이 가능해 진다. 기정의된 IDL 인터페이스를 통해 SOA(Service Oriented Architecture)와 대조되는 개념이다. - client는 어떤 document나 다른 정보 없이 서비스의 하위 정보로 접근이 가능해 지는 이점을 가져갈 수 있다. 기존에 hypertext에서 href를 통해 링크 정보를 내려주는 것과 비슷하다고 볼 수 있다. Hypermedia는 뭐지? - Hypertext의 확정향 개념, hypertext는 일반 text에서 문서간 이동이 가능하도록 hyperlink를 제공해 주었는데, 여기에 Hypermedia는 audio, video까지 포함한 개념으로 이해하면 된다. - 참조 :  https://en.wikipedia.org/wiki/Hypermedia Examples { " content " : [ { " price " : 499.00 , " description " : " Apple tablet device " , " name " : " iPad " , " links " : [ { " rel " : " self " , " href " : " http://localhost:8080/product/1 " } ], " attributes " : { " connector " : " ...

[JAVA] 코딩시 고려해야 할 점 (작성중)

개인적으로 코딩을 하면서 문제발생을 야기했거나, 가독성을 해치는 코드를 만들었던 케이스들을 정리하고 지킬수 있도록 합니다. [한번쯤 생각해 볼만한 Coding Convention] AOP나 intercep등 횡단 관심사의 공통 처리 로직의 경우 최대한 가볍게 만든다. 다수의 query문이나 복잡도가 높은 로직을 실행할 경우 이슈가 발생할 소지가 높다. (게다가 이후에 성능문제가 발생했을때 찾기도 어렵다) switch~case나 try~catch 문등의 묶음 단위로 처리되는 구문안에 들어가는 행을 짧게 만든다. 로직이 길어질경우 break;를 누락하거나 return;문을 누락하는 경우가 매우 많다.한눈에 들어오도록 만들수 있도록 한다. (private나 적절하게 기능을 다른 class에 위임하도록) Controller -> Service -> Repository의 레벨은 될 수 있으면 지키자. 내가 만든 Service의 경우 (예를들면 MemberService)에 개념적으로 다른 부분의 영역을 호출할 경우 (예를들어 Profile)에는 Repository를 직접 가져다 쓰기 보다는 Service를 가져다 사용하도록 한다. CheckedException과 RuntimeException을 잘 구분해서 사용한다. 호출하는 쪽에서 복구처리가 필요하거나 반드시 재처리 해줘야 하는 경우에만 CheckedException을 사용한다. (CheckedException은 남용하지 않는다.) 기본제공되는 Exception을 잘 활용한다. (IllegalArgumentException등..) 다중 if문, 다중 for문은 지양한다. 다중 if문은 가독성을 낮추고(code complexity를 높인다), 다중 for문은 성능에 영향을 미칠 가능성이 높다. (기본적인 Collection 자료구조를 잘 활용하면 이중 for문은 거의 사용하지 않을 수 있다.) private안에 private메소드는 될 수 있으면 지양한다. ...