Java

[Java] 자바의 인자 전달 방식 (call by value와 call by reference)

Junuuu 2022. 2. 27. 00:01
반응형

우선 call by value와 call by reference에 대해 먼저 설명해 드리겠습니다.

 

Call-By-Value (값에 의한 호출)

package javastudy;

public class callByValueTest {

	public static void main(String[] args) {
		int x = 3;
		int y = 5;
		System.out.println(x + " " + y);
		swap(3,5);
		System.out.println(x + " " + y);
	}
	
	static void swap(int x, int y) {
		int temp = x;
		x = y;
		y = temp; 
	}

}

위의 코드의 출력 결과는 어떻게 될까요?

첫 번째 줄에는 당연히 3 5가 출력됩니다.

swap이라는 메서드를 통하여 x, y의 위치를 교체해줬습니다.

 

그러면 두 번째 줄에는 5 3이 출력될까요?

두 번째 줄에도 3 5가 출력됩니다.

 

main에서 쓰이는 변수의 이름 x, y와 swap에서 쓰이는 변수의 이름 x, y가 같기 때문에 더 혼동이 있을 수 있습니다.

main에서 쓰이는 것은 main.x , main.y로 표기하고 swap에서 쓰이는 것은 swap.x , swap.y로 표기하여 설명해 보겠습니다.

 

우선 프로그램이 실행되면 메모리 공간에 main.x 와 main.y 에 각각 3, 5라는 값이 할당됩니다.

따라서 첫 번째 줄에는 3, 5가 출력됩니다.

 

이후에 swap 메서드에 main.x 와 main.y의 값( 3과 5)을 전달하게 됩니다.

swap() 메서드가 실행되면서 메모리 공간에 swap.x 와 swap.y에 각각 3, 5라는 값이 할당됩니다.

즉, 메모리 공간에는 main.x     main.y     swap.x     swap.y 이 4가지가 존재합니다.

swap() 메서드가 종료되면서 swap.y = 3   swap.x = 5 가 할당됩니다.

 

하지만 이 값은 main.x 와 main.y에 영향을 미치지 않습니다.

따라서 두 번째 줄에는 3, 5가 출력됩니다.

 

인자로 실제로 할당된 값(Value)을 주었기 때문에 Call-By-Value라고 불립니다.

 

 

 

Call-By-Reference( 참조에 의한 호출)

package javastudy;

public class callByReferenceTest {
	public static void main(String[] args) {
		int [] array = new int[2];
		array[0] = 3;
		array[1] = 5;
		
		System.out.println(array);
		System.out.println(array[0] + " " + array[1]);
		swap(array);
		System.out.println(array[0] + " " + array[1]);
		
	}
	
	static void swap(int [] array) {
		int temp = array[0];
		array[0] = array[1];
		array[1] = temp;
	}
}

밑에서 더 설명드릴 텐데 사실 Java는 참조에 의한 호출을 하지 않습니다.

그냥 Call-By-Reference는 이런 느낌이 구나 만 이해 하시면 좋을 것 같습니다.

 

System.out.println(array)의 결과는 무엇일까요?

array의 주소 값이 출력됩니다.

출력 예시 : [I@36baf30c

 

첫 번째 System.out.println(array [0] + " " + array [1])의 결과는 무엇일까요?

3 5가 출력됩니다.

 

두 번째 System.out.println(array [0] + " " + array [1])의 결과는 무엇일까요?

이번에는 5 3이 출력됩니다.

 

아까와의 차이점은 swap() 메서드를 호출할 때 값이 아닌 주소를 넘겨주는 차이점이 있습니다.

 

프로그램의 main이 실행되면 메모리 공간에 array라는 참조 변수가 할당되며  array [0] = 3 , array [1] =5라는 값이 저장됩니다.

이후에 이 참조 변수를 swap()에 인자로 전달합니다.

 

swap() 메서드가 실행되면서는 메모리 공간에 temp라는 변수가 할당됩니다.

그리고 사용되는 array [0]과 array [1]은 이미 메모리 공간에 존재하는 array를 사용하기 때문에 값이 바뀌어 저장되는 것이 main의 두 번째 출력에 영향을 주게 됩니다.

 

 

 

Java의 인자 전달 방식

결론적으로는 java는 항상 call by value 방식입니다.

 

첫 번째로 위의 예시처럼 기본 타입이 인자로 전달되는 경우는 이해하기 쉽습니다.

byte, char, short, int, double 등의 기본 타입이 인자로 전달되는 경우에는 위의 call by value 설명에서 언급했던 것과 동일합니다.

 

두 번째로는 객체 레퍼런스가 인자로 전달될 수 있습니다.

저는 이경우가 엄청나게 헷갈렸는데 주소의 값을 넘겨주는 것은 맞지만 객체 그 자체를 넘겨주는 것이 아닌 복사된 주소를 넘겨줍니다.

 

예를 들면 객체 A의 주소가 0이라면 A 그 자체를 넘겨주는 것이 아니라 메서드 내에서 B라는 값에 0을 할당해서 쓴다라고 이해하시면 됩니다.

B의 경우는 메서드가 호출될 때 메모리 공간에 새로 생성될 것이며 메서드가 끝나게 되면 소멸할 것입니다.

 

코드를 통해 살펴보겠습니다.

package javastudy;

class parameter {
	int x;
	parameter(){
		this.x = 10;
	}
}

public class parameterTest {
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub		
		parameter A = new parameter();
		System.out.println(A + " A의 값: " + A.x);
		change(A);					
		System.out.println(A + " A의 값: " + A.x);
		A = new parameter();
		System.out.println(A + " A의 값: " + A.x);
		
	}
	
	static void change(parameter C) {		
		C.x = 5;
		C = new parameter();
		System.out.println(C + " C의 값: " + C.x);
	}

}

parameter라는 객체를 생성하였고 이 객체는 생성될 때 x의 값을 10으로 초기화합니다.

 

출력은 아래의 순서로 이루어집니다.

System.out.println(A + " A의 값: " + A.x);

System.out.println(C + " C의 값: " + C.x);

System.out.println(A + " A의 값: " + A.x);

System.out.println(A + " A의 값: " + A.x);

 

첫 번째 System.out.println(A + " A의 값: " + A.x)의 결과는 무엇일까요?

javastudy.parameter@7a81197d A의 값: 10

A객체를 생성하였고 x의 값은 10으로 초기화되었기 때문에 A의 주소와 10이라는 값이 출력됩니다.

 

System.out.println(C + " C의 값: " + C.x)의 결과는 무엇일까요?

javastudy.parameter@5ca881b5 C의 값: 10

C에 객체를 새로 생성하였기 때문에 x의 값을 10으로 초기화되며 C의 주소가 출력되게 됩니다.

 

제일 중요한 부분입니다.

두 번째 System.out.println(A + " A의 값: " + A.x)의 결과는 무엇일까요?

javastudy.parameter@7a81197d A의 값: 5

change() 메서드는 parameter C를 인자로 사용합니다.

change(A)를 호출하였기 때문에 인자는 A입니다.

A는 참조 변수(객체) 이기 때문에 주소 값을 chagne() 메서드에 넘겨줍니다.

 

그러면 이런 오해가 생깁니다.

A.x = 5;

A = new parameter();

 

이렇게 한 것과 동일한 것 아닌가?

그러면 A의 주소가 출력될 때 C의 주소가 출력되어야 하는 것 아닌가?

 

하지만 Java는 call by value만 지원한다고 앞서서 말씀드렸습니다.

따라서 A의 주소를 사용하지만 B라는 값에 A의 주소를 복사하여 사용합니다.

 

사실은 이렇게 사용되고 있습니다.

B.x = 5;

B = new parameter();

 

따라서 B는 A의 주소를 사용하기 때문에

B.x = 5에서 A.x =5랑 동일한 효과가 있습니다.

하지만 B = new parameter();는 단지 B에 새로운 주소를 할당하는 것입니다.

그리고 메서드가 끝나게 되면 B는 소멸됩니다.

 

따라서 주소를 복사해서 사용하는 것 이기 때문에 A의 주소에는 영향을 줄 수 없습니다.

 

마지막 System.out.println(A + " A의 값: " + A.x)의 결과는 무엇일까요?

javastudy.parameter@24d46ca6 A의 값: 10

A = new parameter()를 통하여

이번에는 새로운 객체를 생성했기 때문에 A에는 새로운 주소와 10이라는 값이 출력됩니다.

 

 

출처

https://joooootopia.tistory.com/3

 

함수 호출 시 인자 전달 방식 : call by value와 call by reference

함수 호출 시 인자 전달 방법에는 Call-by-value(값에 의한 호출)와 Call-by-reference(참조에 의한 호출)이 있다. 본 포스팅에서는 먼저 이 둘을 비교하며 설명한 후, 현재 공부하고 있는 java의 인자 전달

joooootopia.tistory.com