-
[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
'Java' 카테고리의 다른 글
[Java] BufferedWriter vs println 속도분석 (0) 2022.03.04 [Java] Java8 default 인터페이스 (0) 2022.02.28 [Java] 이클립스 글자 안 보일 때 해결 방법(이클립스 흰 화면 출력 시 해결 방법) (0) 2022.02.26 [Java] DTO, DAO, VO란? (0) 2022.02.19 [Java] Optional이란? (0) 2022.02.11