ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 자바의 인자 전달 방식 (call by value와 call by reference)
    Java 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

     

    댓글

Designed by Tistory.