메소드(함수) 호출 방식

프로그래밍 언어에서 변수를 다른 함수의 인자로 넘겨 줄 수 있습니다.

이 때 이 변수의 '값'을 넘겨 주는 호출 방식을 Call by Value 

이 변수의 '참조값' (혹은 주소, 포인터)를 넘겨 주는 호출 방식을 Call by Reference라고 합니다. (이외에도 Call by Assignment, Call by Name 등의 개념이 있다고 들었습니다.)

자바는 Call by Value 방식으로 동작하게 되는데 이를 증명 해 볼 수 있는 대표적인 예제가 변수의 값을 바꿔보는 함수(메소드)가 있습니다.

 

public static void main(String[] args) {
    int a = 1;
    int b = 2;
    swap(a, b);

    System.out.println(a); //출력결과 1
    System.out.println(b); //출력결과 2
}

static void swap(int a, int b) {
    int tmp = a;
    a = b;
    b = tmp;
}

위와 같이 두개의 변수를 간단히 바꿔보는 메소드를 만들어서 실행 후 출력 해보면,

인자로 넘겨주었던 변수들의 값이 변경 되지 않고,

main() 에서는 그대로 출력 되는 것을 알 수 있습니다.

자바의 함수(메소드) 호출 방식이 Call by Value 이기 때문입니다. (만약 Call by Reference 였다면 값이 바뀌게 됩니다.)

 

자바의 참조형은 Call by Reference 인가?

자바의 함수(메소드) 호출 방식에 대해서 공부하다가 꽤 흥미로운 사실을 알게 되었습니다. 자바의 기본형은 Call by Value가 맞지만, 참조형은 Call by Reference가 맞다는 의견도 있고 / 기본형과 참조형 모두 Call by Value가 맞다는 의견도 있었습니다. 또한 중립적으로 이견이 있음을 인정하는 의견도 있었습니다. 왜 이런 이견이 생기는 걸까요?

1. 참조 바꿔보기

어떠한 부분이 자바 개발자들에게서 이견이 생기는지 코드로 알아 보도록 하겠습니다.

class MyClass{
    int index;

    public MyClass(int index) {
        this.index = index;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}
public class JavaCallByValue {
    public static void main(String[] args) {
        MyClass myClass1 = new MyClass(1); // 인스턴스 만들어서 myClass1 에 1을 대입한다
        MyClass myClass2 = new MyClass(2); // 인스턴스 만들어서 myClass2 에 2를 대입한다

        //두개의 참조를 바꿔 보자
        swapReference(myClass1, myClass2);
        System.out.println(myClass1.getIndex()); //출력결과 1
        System.out.println(myClass2.getIndex()); //출력결과 2
    }

    static void swapReference(MyClass m1, MyClass m2) {
        MyClass tmp = m1;
        m1 = m2;
        m2 = tmp;
    }
}

필드가 하나 있는 간단한 클래스(MyClass)를 선언했습니다.

그리고 MyClass 2개를 생성하고 각각의 index 필드 값을 1과 2로 지정 했습니다.

 

swapReference() 메소드를 이용해서 두 개의 참조를 바꿔 보면, 필드 값이 바뀌지 않고 1, 2로 출력되게 됩니다. 

이런 부분을 보면 자바가 Call by Reference가 아님을 알 수 있습니다. 

참조형을 사용 하더라도, 두 개의 참조를 바꾸는 일은 안되기 때문입니다.

만약 진정한 Call by Reference라면 참조가 바뀌는 일도 가능해야 합니다.

 

2. 필드 값 바꿔보기

class MyClass{
    int index;

    public MyClass(int index) {
        this.index = index;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}
public class JavaCallByValue {
   public static void main(String[] args) {
        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
   }

   static void swapValue(MyClass m1, MyClass m2);{
        int tmpIndex = m1.getIndex(); // m1의 리턴값 1을 tmpIndex에 저장
        m1.setIndex(m2.getIndex());   // m2의 리턴값 2를 m1의 setIndex로 처리
        m2.setIndex(tmpIndex);        // tmpIndex 값을 m2의 setIndex로 처리 
    }

이번에는 참조가 아닌 각각의 필드 값을 Getter/Setter를 이용해서 바꿔보았습니다.

그런데, 예외적으로 이런 경우에는 두개의 값이 변경됩니다.

이런 부분 때문에 참조형이 Call by Reference라는 오해를 받게 된다고 생각합니다.

왜 이런 부분이 가능할까요? 

 

자바가 함수의 인자로 전달해주는 것은 어떤 것을 참조 하고 있는지에 대한 참조 값을 전달하기 때문입니다. 

1번 예제에 경우 참조값을 받아서 그 참조값들을 다른 스택(함수)에서 변경하는건 아무런 의미가 없습니다.

 

하지만 참조값을 받아서 그 참조값을 이용하는 것은 가능하기 때문입니다.

자바에서 객체를 컨트롤 하는 행위는 어떤 장소이든 간에 그 객체를 참조하는 참조값만 알고 있다면 가능합니다. (접근제어자로 막혀있지 않은 한) 그래서 2번 예제에 같은 경우가 가능한 것 입니다.

 

결론

자바의 참조형이 Call by Value냐 Call by Reference냐 라는 물음에 대한 답은 Call by Value가 맞는 것 같습니다. 그런데 제가 공부하면서 느낀 건 자바의 참조형이 Call by Reference인지 아닌지 엄밀히 구분할려는 것 자체가 무의미 하다는 것입니다. 이런 혼동의 원인은 아마도 C언어에 익숙한 프로그래머 들의 잔재(?)가 아닐까 합니다. 애초에 C언어에서는 Call by Value와 Call by Reference를 문법적으로 구분이 가능하지만, 자바는 문법적으로 구분이 불가능 합니다. 자바의 메소드(함수) 호출 방식은 그냥 자바의 호출 방식으로만 이해하면 됩니다.


자바에서 제공하는 this 키워드는 인스턴스 자기 자신를 가리키는 키워드입니다. 이 this 키워드를 통해 클래스 메서드 및 생성자에서 자기 자신의 데이터를 업데이트하거나 조작할 수 있습니다.

 

여기서 중요한 것은 this 키워드는 이 클래스를 기반으로 생성된 인스턴스를 가리키는 참조라는 사실입니다. 인스턴스를 가르키는 참조와 인스턴스 자체는 다르다는 것을 알아두셨으면 좋겠습니다.

 

 

'📌 java > Object-oriented Programming' 카테고리의 다른 글

Homework_W3  (0) 2020.03.31
java - accesor, mutator  (0) 2020.03.31
java - public의 의미  (0) 2020.03.27
Homework_W2-02  (0) 2020.03.27
Employee.java  (0) 2020.03.27
복사했습니다!