Java/Grammer

Call by value

2021. 12. 28. 07:01

함수 호출 시 매개변수로 전달받은 인자는 원본 데이터일까요?

우리 자바는 "원본 데이터가아닌 복사한 값을 전달받는 Call by value 방식"을 사용합니다.

예시를 통해 알아봅시다.

public class CallByValue {
	public static void toZero(int data) {
		data = 0;
	}
	
	public static void main(String[] args) {
		int data = 100;
		System.out.println("호출 전 : " + data);   //호출 전 : 100
		toZero(data);
		System.out.println("호출 후 : " + data);   //호출 후: 100
	}
}

toZero() 메서드 내에서 원본 데이터를 변경하려 했지만 변경이 되지 않은 모습입니다.

 

 

그렇다면 원본 데이터의 훼손이란 불가능한 걸까요?

아닙니다. 값을 전달받더라도 "원본 데이터는 훼손 가능"합니다.

public class CallByValue {
	public static class Me {
		int data = 100;
	}
	
	public static void toZero(Me me) {
		me.data = 0;
	}
	
	public static void main(String[] args) {
		Me me = new Me();
		System.out.println("호출 전 : " + me.data);   //호출 전 : 100
		toZero(me);
		System.out.println("호출 후 : " + me.data);   //호출 후 : 0
	}
}

위와 같이 원본 데이터를 훼손시킬 수 있기 때문에 예전에는 Call by reference 방식이라 주장도 꽤나 존재했습니다.

그렇지만 현재 대부분의 사람들이 자바는 Call by value 방식이다라는 의견에 동의를 합니다.

 

다음 예시를 보시죠.

public class CallByValue {
	public static class Me {
		int data;
		public Me(int data) {
			this.data = data;
		}
	}
	
	public static void toZero(Me me) {
		me = new Me(0);
		System.out.println("호출 중(복사 데이터) : " + me.data);   //호출 중(복사 데이터) : 0
	}
	
	public static void main(String[] args) {
		Me me = new Me(100);
		System.out.println("호출 전(원본 데이터) : " + me.data);   //호출 전(원본 데이터) : 100
		toZero(me);
		System.out.println("호출 후(원본 데이터) : " + me.data);   //호출 후(원본 데이터) : 100

	}
}

만일 Call by reference라면 호출 후에도 값이 변경되어 있어야 합니다.

하지만 원본 데이터는 신기하게도 멀쩡합니다.

그 이유는 원본 데이터에 대한 참조를 값으로 전달받았고 해당 변수는 그 참조를 다른 값으로 교체했기 때문입니다.

 

참조값을 넘기는데 어떻게 Call by reference가 아니냐 하실수 있습니다.

물론 이 논의도 참조를 어떻게 해석하냐에 따라 의견이 갈리고 저 또한 C언어를 먼저 배웠기에 많은 혼란이 있었습니다. 여기서 중요한 점은 "자바에서 참조값을 넘긴다는 말의 의미는 Call by reference에 해당하지 않는다" 정도로 이해하시면 되겠습니다.

 

 

 

참고

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