Hun's Blog

[JAVA] Call by value와 Call by reference 본문

Language/Kotlin & Java

[JAVA] Call by value와 Call by reference

jhk-im 2020. 3. 21. 23:09

Call by value


= 값에 의한 호출

프로그래밍 언어에서 변수를 다른 메소드의 인자로 넘겨 줄 수 있다. 이때 변수의 '값'을 넘겨주는 호출 방식을 Call by value 라고한다.

자바는 Call by value 방식으로 동작한다.

예제  

1
2
3
4
5
6
7
8
9
10
11
12
static void swap(int x,int y){
    int tmp = x;
    x = y;
    y = tmp;
}
 
//main() 호출 및 결과
int a = 1;
int b = 2;
swap(a,b);
System.out.println(a); // 1 
System.out.println(b); // 2
 

 

swap() 은 입력값 x와 y의 값을 바꾸는 예제이다. a = 1, b = 2가 입력되고 바뀐것이니 println() 을 했을때 바뀌어서 출력될 것 같지만 그대로 출력된다. 입력된 인자 a,b 와 swap() 의 x,y 는 서로 다르기 때문이다.

main()에서 선언 된 변수 a,b 각각 의 메모리에 할당 되었다고 생각해 보자. 할당 된 메모리 변수에는 각각 10과 20의 값이 저장된다. 이후 swap() 호출 시 입력한 a,b는 메모리 주소가 아닌 메모리에 담겨져 있던 값만 복사되어 swap() 내부의 x와 y의 메모리 주소에 담겨지게 된다. swap() 이 실행 되더라도 입력된 a,b 는 main의 a,b 가아닌 swap() 내부에 복사되어 새로 생성된 x,y 이기 때문에 수행 후에도 결과 값에 변화가 없는 것이다.

*Call by value란 - 메소드 호출 시 입력되는 인자의 메모리 주소가 아닌 메모리에 저장되어 있는 값을 복사하여 보낸다.


Call by reference


= 참조에 의한 호출

메소드 호출 시 입력하는 인자가 값이 아닌 주소를 넘겨줌으로 써 , 주소를 참조(Reference)하여 데이터를 변경할 수 있다.

자바의 참조형은 Call by reference 인가? 
자바의 기본형은 Call by value가 맞지만, 참조형은 Call by reference가 맞다는 의견, Call by value 라는 의견, 중립적인 의견 으로 이견이 생긴다고 한다.
어떠한 부분에서 이견이 생기는지 알아보자

예제

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
29
class MyClass{
    int index;
    public MyClass(int index) {
        this.index = index;
    }
    public int getIndex() {
        return index;
    }
    public void setIndex(int index) {
        this.index = index;
    }
}
//필드가 하나 있는 클래스(MyClass)를 선언하였다.
 
main()
static void swapReference(MyClass m1, MyClass m2) {
    MyClass tmp = m1;
    m1 = m2;
    m2 = tmp;
}
//MyClass를 입력값으로 받아 두개의 참조를 바꾼다.
 
//main() 호출 및 결과
MyClass myClass1 = new MyClass(1);
MyClass myClass2 = new MyClass(2);
//두개의 참조를 바꿔 보자
swapReference(myClass1, myClass2);
System.out.println(myClass1.getIndex()); //1
System.out.println(myClass2.getIndex()); //2
 

MyCalss 2개를 생성하여 index 필드 값을 1과 2로 지정하였다.
swapReference() 메소드를 사용해서 두개의 참조를 바꿔보면,
바뀌지않고 1,2 가 출력된다. 자바는 참조형을 사용 하더라도, 두개의 참조를 바꾸는 일은 안되기 때문에 Call by reference가 아님을 알 수 있다.

 

필드 값을 바꿔보기

1
2
3
4
5
6
7
8
9
10
11
12
13
static void swapValue(MyClass m1, MyClass m2){
    int tmpIndex = m1.getIndex();
    m1.setIndex(m2.getIndex());
    m2.setIndex(tmpIndex);
}
 
//main() 호출 및 결과
MyClass myClass1 = new MyClass(1);
MyClass myClass2 = new MyClass(2);
//두개의 필드 값을 바꿔보자
swapValue(myClass1, myClass2);
System.out.println(myClass1.getIndex()); //2
System.out.println(myClass2.getIndex()); //1
 

이번에는 참조가 아닌 각각의 필드 값을 getter/setter를 사용해서 바꿔 보았다. 이번에는 두개의 값이 변경되었다. 이 부분이 참조형은 Call by reference라고 생각할 수 있다.

이 경우는 왜 가능한 것일까? 
main()에서 선언된 MyClass 타입의 변수 myClass1과 myClass2는 각각 객체를 생성하여 생성자로 입력받은 1,2를 각자의 위치에 주소값으로 저장한다. 이후, swapValue() 메소드 호출시 입력된 myClass1,myClass2 는 메모리에 저장된 주소값을 복사하여 매개변수 m1,m2의 메모리에 저장한다. 결국 swapValue()에 입력된 1,2가 저장된 각각의 주소를 참조하고 getter / setter 를 통해 원본에 접근하여 연산하기 때문에 결과에 따라 원본 데이터가 변하게 된다.

*자바는 메소드의 인자로 참조형을 받으면 어떤 것을 참조하고 있는지에 대한 참조값을 전달한다는 것을 기억하자.

*swapReference() 처럼 참조값을 입력받고 나서 메소드 내부에서 변경하는 것은 다른 스택에서 변경하는 것이기 때문에 의미가 없다.


정리 - 
자바는 기본적으로 Call by value = 값에 의한 호출 방식으로 동작한다. 
변수가 선언되고 변수에 값을 넣은다는 것은 메모리에 값이 할당되었다는 의미이다. 이 값을 메소드의 입력값에 인자로 전달하면 자바는 메모리에 있는 값을 복사해서 전달한다. 원본이 아닌 복사된 '값'을 전달하는 것이 Call by value이다. 
복사된 값이 전달되었다는 것은 새로 생성된 값이며 원본과 분리 되었다는 의미이고 그렇기 때문에 복사본을 아무리 변경하여도 원본에는 아무런 변화가 없다.

String s = new String("hi");
자바에서는 위의 s를 참조형이라고 부른다. 이러한 참조형이 메소드의 입력값에 인자로 전달하면 자바는 메모리에 있는 참조형의 주소값을 전달한다. 이때 전달 받은 값을 메소드 내부에서 변경했을 때에는 주소값에 있는 값을 다시 복사해서 '값'만 사용하기 때문에 Call by value 처럼 원본에 아무런 변화가 없다. 하지만 이 참조형의 주소값으로 getter / setter 를 활용하여 원본에 접근할 수 있는 상황이라면 메소드 내부에서 원본값을 변경 할 수 있게된다. 

이 부분에서 자바의 참조형이 Call by value다 Call by reference 혹은 중립이다 라는 이견이 갈리는데 사실 지금까지 내가 이해한 바로는 주소값을 전달 받아서 그 주소로 직접 접근해서 원본을 바꾼다고 이해하였고 getter / setter 로 접근하지 않고 전달받은 주소값을 그냥 사용하면 전달받은 주소값에 있는 값을 복사해서 사용하기 때문에 메소드 내부에서의 값 변경이 원본에 영향을 미치지 않는 것으로 보아 Call by value 라고 약 80%정도 .. 



https://re-build.tistory.com/3
https://siyoon210.tistory.com/104

 

자바의 메소드(함수) 호출 방식 - Call by Value vs Call by Reference

메소드(함수) 호출 방식 프로그래밍 언어에서 변수를 다른 함수의 인자로 넘겨 줄 수 있습니다. 이 때 이 변수의 '값'을 넘겨 주는 호출 방식을 Call by Value, 이 변수의 '참조값' (혹은 주소, 포인터)를 넘겨 주..

siyoon210.tistory.com

 

[Java] Call by value와 Call by reference

이번에 다룰 주제는 Call by value, Call by reference 입니다. 함수의 호출 방식에는 Call by value와 Call by reference가 있습니다. 말 그대로 '값에 의한 호출'이냐, '참조에 의한 호출'이냐 라고 할 수 있는..

re-build.tistory.com