[JAVA] "JAVA에는 call-by-reference가 없다!"

RisingJade의 개발기록·2022년 3월 13일
1

자바에는 Call-By-Reference 가 없다!


1. 분명 자바를 쓰면서 함수에 클래스를 넘기고 내부 변수를 변경하면 바뀌던데...?

class A{
		public int value;
		A(int i){
			this.value = i;
		}
		
	}

	void run( A arg1, A arg2){
		arg1.value = 111;
        arg2 = arg1;
	}
	public static void main(String[] args){
		A a1= new A(1);
		A a2= new A(2);
		run(a1,a2);
        System.out.println(a1);
        System.out.println(a2);
	}
    
______console______
111
2
  • 위의 결과를 보면 분 ㅡ 명 a1은 111로 바뀌었기 때문에 reference로 주었다고 생각할수도 있다.
    하지만 정확히 말하면 저건 ref를 준 것이 아니라 a1의 주소를 복사해서 바꾼것이다.

  • 사실 C++ 기준으로 보면 저것도 call-by-reference의 일종이라 생각된다.

  • 아래는 윤성우의 열혈 C++에서 발췌한 내용이다.

    "본래 C언어에서 말하는 Call-by-Reference는 다음의 의미를 갖는다."

    "주소 값을 전달받아서, 함수 외부에 선언된 변수에 접근하는 형태의 함수 호출"

    "즉, 주소값이 외부 변수의 참조도구로 사용되는 함수의 호출을 뜻한다. 이렇듯 주소 값이 전달되었다는 사실이 중요한게 아니라, 주소값이 참조의 도구로 사용되었다는 사실이 중요한 것이며, 이것이 Call-by-ValueCall-by-Reference를 구분하는 기준이 된다!"

  • 아니 분명 우리 늅늅이 개발자들의 희망 윤성우 선생님께서 주소 값 받아서 함수 외부에 선언된 변수에 접근하면 call-by-reference라는데??

    • 왜? 아니죠...?

      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.

  • 일단 자바 창시자님이 아니라니까 아닌건가 본데...

2. 그래서 왜 자바에 call-by-reference가 없다는건데...?

위의 유명한 스택오버플로우 답변이있다. 위 말을 정리하면

  • "우리가 객체를 다룰 때는 실제로 참조라고 하는 객체 핸들도 다루게 됩니다. 이 객체 핸들도 가치(value)로 전달됩니다"

이...이게.. 무슨말이요...

이해가 안가서 곰곰히 생각해보고 내린 결론은, 분명 객체를 받을 때 우리가 "참조"라고 생각하는 그 객체 다루는 기법? 마저도 value라는 가치로 전해진다는 것이다.
쉽게 생각해서 그냥 주소값만 복사해서 매개변수에 갖다 줬다고 생각하자 C++에서

Func(SampleClass* a){....} 
SampleClass *b = new SampleClass();
Func(b) 

이렇게 하면 SampleClass* b가 가리키는 주소와 a가 가리키는게 같아지고 요런 느낌으로 전해준다고 생각하면 된다.

  • (이것도 엄밀히 말하면 잘못된 이해라고 생각한다. 흔히 C++에서 말하는 call-by-address 개념과 비슷하게 설명한건데, 위의 윤성우 C++ 발췌에서 보았듯이 뭐가 됬든, 외부에 선언된 변수에 접근하는 함수의 호출이면 call-by-reference다. 하지만 자바에선 그냥 call-by-value다. 그 주소를 넘기는 핸들 자체도 value라는 가치에 담아서 넘겨주기 때문이다...)

하지만 확실히 C++ ref같은 건 아니다. ref 처럼 아예 참조(별칭)을 붙여서 넘겼다면 위의 코드의 run()에서 arg2 = arg1하고나면 A a2도 111이여야되는데 아니지 않나. 그 이유는 아래서 더 자세히 설명하겠다.

자 코드를 다시 봐보자

여기서 arg2 = arg1 해봤자

이렇게 바뀌고 run이라는 함수에 나와도 a2는 멀뚱멀뚱하게 value=2를 바라본다.

그림 참조: https://deveric.tistory.com/92

3. 결론

  • 분명 객체를 넘길 때 참조값(주소값)처럼 보이고 실제로도 같은 힙영역을 공유하지만, 참조값을 호출한게 아니라 그냥 참조"값"을 복사해서 매개변수에 넘겨준것이라고 생각하자! ( 더 정확히 알고 싶으면 자바 창시자의 글을 읽어라...
    The Java Programming Language, 2nd ed. by Ken Arnold and James Gosling)
profile
언제나 감사하며 살자!

0개의 댓글