Skip to content
Sanghyuk Jung edited this page Aug 7, 2024 · 2 revisions

회사 소모임의 세미나 때 나왔던 잠시 논의되었던 내용이였는데 정리해 보았습니다.

java에 대한 오해를 몇가지 이야기하면서 들었던 주제였는데요, 제가 이 이야기를 꺼낸 이유는 지난주에 어느 게시판에서 다음과 같을 글을 보았기 때문입니다.

아래는 제가 위에 글에 관련 글을 쓰면서 달았던 참고링크입니다.

  1. http://javadude.com/articles/passbyvalue.htm

  2. http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html

  3. http://blog.naver.com/eureka922?Redirect=Log&logNo=10002121890 요지는 java의 메서드 호출은 무조건 pass by value이다. primitive type은 pass by value, object는 pass by reference라고 말하고 다니는 사람이 있는데, 그건 흔한 오해다.. 이런 내용입니다. Object의 경우도 참조값의 복사가 넘어가므로 primitive와 다를 바가 없다는 거죠.

아래코드의 값을 실행시켜 보시면 아실수 있습니다.

public class MyTest3 {
     public static void main(String[] args) {
         StringBuffer sb = new StringBuffer();
         sb.append("3333");

         work(sb);
         System.out.println(sb);

     }

     static void work(StringBuffer sb){

         sb = new StringBuffer();

         sb.append("!11111");

     }

 }

위에서 sb = new StringBuffer() 부분이 있을때와 없을때의 결과를 비교해 보시기 바랍니다.

다음은 첫번째 링크에서 따온 예제를 가지고 한 설명입니다.

자바에서는

Dog d;

d.setName("Fifi");

C or C++'에서는 정확히 다음과 같습니다.

Dog *d; // C++ // 생략..

d→setName("Fifi"); // C++ java

자바의 디자이너는 아마도 C와 C++의 포인터와 다르다는 것을 강조하기 위해 pointer라는 말을 감추고 reference라는 용어를 사용하고 있는데, 그것이 더 혼동을 가지고 온 선택이였다는 의견이 있습니다.

Dog d;

를 선언하는 것은 Dog object에 대한 pointer를 선언하는 것이지 Dog object 그 자체를 선언하는 것이 아닙니다. 따라서 d의 값이라는 것은 힙메모리에 있는 객체자체가 아닌 주소값 같은 것, d가 가리키는 힙메모리에 있는 객체와 연결을 위한 값이라고 할 수 있습니다. 그 주소같은 값을 메소드값 호출시에 복사해서 넘기고, 메서드 내에서 그 주소값이 다른 객체를 가리키는 값으로 바뀌었다고 해도 메서드밖으로 전달이 안 됩니다. 그래서 call by value인 것이죠. "참조의 복사본"이 넘어간다는 말이 이런 말입니다. 대신 그 넘어간 주소값을 통해서 그것이 가리키는 객체의 멤버변수나 배열의 요소에 대해서는 변경을 할 수 있겠죠.

pass by reference와 pass by value의 정의에 대해서는 다음의 링크를 참고하시기 바랍니다.

java의 reference 타입이 매개변수로 넘어갔으니 pass by reference라고 연상되기 쉬운, 용어상의 혼란도 이 오해의 한 원인인것 같습니다.

제일 위에 건 2번 링크를 보면 쓰인 시점이 2000년도인데 그때도 이미 "I’m really tired of hearing folks (incorrectly) state "primitives are passed by value, objects are passed by reference. - 그런 말 듣는데 지쳤다." 라는 쓰고 있습니다. 첫번째 링크는 오죽했으면 제목 뒤에 'damm it!'이 붙어있습니다.

사실 저도 java를 처음 배운건 1999년이였는데 2004년정도가 되어서야 이 사실을 알게 된것 같습니다 ^^; 아마도 java를 쓰는 동안은 계속 반복될 질문과 답변이 아닐까하는 생각도 드네요.


이에 대한 언급한 다른 자료들

Java Language Spec

http://www.javaranch.com/campfire/StoryCups.jsp http://www.javaranch.com/campfire/StoryPassBy.jspHead first java 4장, 객체의 행동(번역판 111페이지)

Refactoring, 번역판 161페이지. "Java는 엄격하게, 모든 경우에 값에 의한 전달을 사용한다"

전문가가 들려주는 java이야기 58쪽

https://www.facebook.com/tobyilee/posts/10222585502760852
public class ReferenceTest {
	public static void main(String[] args) {
		String x1 = "Hello";
		String y1 = "World";
		swap(x1, y1);
		System.out.println(x1);

		int x2 = 1;
		int y2 = 2;
		swap(x2, y2);
		System.out.println(x2);

	}

	static void swap(Object x, Object y) {
		Object temp = x;
		x = y;
		y = temp;
	}
}

-"World"가 나온다고 말하면 틀린 대답입니다. - x1,y2가 안 바뀌어서 "Hello"가 나온다고 대답하면 그렇다면 왜 Java에서 객체타입은 call by reference로 전달된다고 생각하는지 물어볼 수 있습니다.

제임스 고슬링의 언급을 참고하여 정리하자면 Java 메서드 호출은 'Call by value’로, '객체에 대한 레퍼런스 값’이 전달된다 더 정확한 대답입니다.

Clone this wiki locally