함수 호출 시 인자 전달 방법에는 Call-by-value(값에 의한 호출)와 Call-by-reference(참조에 의한 호출)이 있다. 본 포스팅에서는 먼저 이 둘을 비교하며 설명한 후, 현재 공부하고 있는 java의 인자 전달 방식에 대해서도 설명할 것이다
Call-By-Value (값에 의한 호출)
코드가 진행되는 순서대로 설명하겠다. 위는 call by value방식의 함수(swap)가 구현된 프로그램이 메모리에 할당되고, 흘러가는 방식을 도식화하여 나타낸 그림이다.
먼저 프로그램이 실행되면, 초기화한 변수에 대한 메모리 할당이 발생할 것이다. 메모리에 origin1과 origin2변수의 공간을 만들어, 그 값을 각각 10과 20으로 저장하는 작업이다. -- (1)
여기서, printf("first : %d, %d", origin1, origin2); 는 first : 10, 20 을 출력한다.
그 다음으로 함수 swap(origin1, origin2); 가 호출되면, 변수 origin1과 origin2의 값들은 각각 a와 b로 대입되어 들어간다. 이 때, origin1과 origin2는 '인자'가 되는 것이며 호출된 함수 swap은, main함수 변수들의 값(value)만을 가져다가 메모리에 공간을 할당받아 저장하게 되는 것이다. -- (2)
호출된 swap() 함수는 코드에서 선언된 순서대로, 변수 a와 b값을 서로 맞바꾼다. (이 글은 call by value에 대해서 설명하고자 하므로 코드에 대한 자세한 설명은 생략한다.) 그럼, a = 20, b = 10이 된 채로 swap함수는 종료하게 된 것이다. 하지만, 그림상의 메모리 공간에서 보여지듯, swap 함수와 main 함수는 메모리 상 별개의 공간에 자리하고 있으며, swap 함수의 실행 결과는 main 함수에 아무런 영향을 끼치지 않는다. 즉, 함수 swap이 종료됨과 동시에 a와 b는 소멸한 것이고, 당연히 a = 20, b = 10 이라는 결과도 소멸된 것이다. 이렇게 swap 내에서 치환된 변수값은 결국 swap()함수 내에서만 유효한 셈이다. -- (3)
따라서, main함수로 다시 돌아와 실행되는 printf("second : %d, %d", origin1, origin2); 는 second : 10, 20 을 출력한다.
만약, 각각 20과 10으로 치환된 변수 값을 출력하고 싶다면, printf문을 swap()함수 내에서 작성해야 할 것이다.
Call-By-Reference (참조에 의한 호출)
마찬가지로, 프로그램의 흐름에 따라 설명하겠다. 위는 call by reference방식의 함수(swap)가 구현된 프로그램이 메모리에 할당되고, 흘러가는 방식을 도식화하여 나타낸 그림이다.
프로그램이 최초로 실행되면, 메모리에 main함수의 멤버변수인 origin1과 origin2에 대한 메모리 상 공간이 생기고, 각각 10과 20이라는 변수값을 할당해 줄 것이다. -- (1)
Call by value에서와 같이, 여기서 printf("first : %d, %d", origin1, origin2); 는 first : 10, 20 을 출력한다.
그 다음으로 함수 swap(&origin1, &origin2); 가 호출되면, swap()함수의 인자로서 origin1과 origin2의 주소값인 &origin1(0X0005)과 &origin2(0X0009)가 각각 a와 b의 포인터변수로 넘어간다. 결국, swap()이 호출되면 메모리 공간에서 가장 먼저 일어나는 변화는, int *a = 0X0005; int *b = 0X0009 가 되는 것이다. -- (2)
이제, swap() 함수가 넘겨받은 origin1과 origin2의 주소를 참조하여 치환을 한다. (함수 실행) swap() 함수의 변수들은 (temp를 제외하고) 포인터 변수들이며, 해당 포인터 변수의 주소를 참조하여 값을 연산하게 되므로, 실질적으로는 참조된 주소값에 해당하는 main함수의 origin1값과 origin2값이 변경되는 것이다. -- (3)
따라서, main함수로 다시 돌아와 실행되는 printf("second : %d, %d", origin1, origin2); 는 second : 20, 10 을 출력한다.
그렇다면 call by value와 call by reference는 어떤 면에서 trade-off 관계를 유지할까?
먼저, call by value의 경우 함수 호출을 할 때마다 값(데이터)을 복사하여 함수로 인자 전달하고, 이렇게 인자 전달이 발생할 때마다 메모리 공간이 할당되기 때문에 메모리 공간의 낭비를 초래할 수 있다.
call by reference의 경우 call by value가 초래하는 메모리 공간 낭비 문제는 거의 발생하지 않지만, 원본 데이터(값)가 손상될 수 있다는 문제점이 있다
Java의 인자 전달 방식
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class Myname { String myname; Myname(String n){ //생성자 myname = n; } } public class CallByValue{ public static void main(String[] args) { Goods g = new Goods(); //Goods 객체 생성 Myname m = new Myname("computer"); //Myname 객체 생성 System.out.println(m.myname); --(1) g.setName(m); //레퍼런스 복사 ----------★ System.out.println(m.myname); --(2) } } class Goods{ public String name; public void setName(Myname a) { name = a.myname; a.myname = "pencil"; } } | cs |
그림 속 1) 부터 차례로 살펴보겠다. 먼저, 프로그램이 최초로 실행된 후 Myname m = new Myname("computer"); 코드가 실행된다면, Myname 객체가 생성되며, a가 Myname 객체를 가리키게 된다. g.setName(m); 코드가 실행되어 m값이 setName() 메소드에 전달되면 m값도 a에 전달되고, public void setName(Myname a) 가 호출됨에 따라 메소드 인자 a는 m이 가리키는 Myname 객체를 동시에 가리키게 된다. (레퍼런스 복사)
2) 로 넘어와보자. a.myname = "pencil"; 이 실행되면 setName 메소드 내에서 a가 가리키는 객체 필드 myname 값이 변경된다. 그렇게 되면 그림에서 보이는 바와 같이, 객체 m의 필드 myname을 변경한 것과 같아지게 된다.
3) setName() 메소드가 종료됨과 동시에, 레퍼런스 a는 사라지고, m은 그대로 "pencil" 이라는 값을 가진 myname 필드를 가리키고 있는 꼴이 되므로, System.out.println(m.myname); --(2) 이 실행되면, 이 출력된다. 물론, System.out.println(m.myname); --(1) 에 해당하는 출력은 이다. 이 코드를 실행하고 나면 java가 사실 call by reference를 채택하는 것과 같은 셈이 아닌가 하는 의문지 들 수 있다.
하지만 위 코드를 이와 같이 변경해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class Myname { String myname; Myname(String n){ //생성자 myname = n; } } public class CallByValue{ public static void main(String[] args) { Goods g = new Goods(); //Goods 객체 생성 Myname m = new Myname("computer"); //Myname 객체 생성 System.out.println(m.myname); g.setName(m); //레퍼런스 복사 System.out.println(m.myname); } } class Goods{ public String name; public void setName(Myname a) { name = a.myname; //a.myname = "pencil"; a = new Myname("pencil"); } } | cs |
'Study > CS' 카테고리의 다른 글
Java 의 개발 철학과 특징 (0) | 2020.05.28 |
---|---|
컴퓨터 네트워킹 : network core (0) | 2018.10.15 |
컴퓨터 네트워킹 : network edge, access network, 물리 매체들 (0) | 2018.10.13 |