JAVA Call By Reference? Value?

Posted by 열정보이
2019. 3. 3. 15:15 JAVA

JAVA는 Call By Reference인가 Value인가에 대한 논의가 많은 것 같습니다.

먼저 int, double, long, char, boolean 등과 같은 기본 자료형에 대해서는 Call By Value가 맞습니다.


다음 예제를 보시죠.


1
2
3
4
5
6
7
8
9
10
11
12
13
public class CallByValue {
    public static void main(String[] args) {
        int testValue = 10;
        check(testValue);
        System.out.println("확인 : " + testValue);
    }
    
    public static void check(int i) {
        i = 20;
        return;
    }
    
}
cs


check 메서드에서는 파라미터로 받은 i에 대한 값을 변경해주는 메서드입니다.

하지만 메서드를 실행 후 출력을 해보면 20이 아닌, 원래 값인 10이 나오는걸 알 수 있습니다.



왜냐하면 파라미터로 받은 i 는 참조변수 testValue가 참조하는 데이터에 대한 주소값이 아닌, 

testValue가 참조하는 '값을 복사'해서 보내는 것이기 때문입니다.


위와 같은 방법을 Call By Value라고 합니다.

파라미터로 오직 값만 보내는 것을 Call By Value라고 하죠.

Java가 기본형에 대해 Call By Value인 이유는, 기본형에 대해 주소값을 보내는 방법이 존재하지 않기 때문입니다.


C언어를 생각해보면, 포인터를 통해서 주소값을 보낼 수 있죠.

하지만 Java에서는 주소값을 보낼 수 있는 어떠한 방법도 존재하지 않습니다.


그렇기 때문에 기본 자료형에 대해서는 100% Call By Value다.

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
public class CallByValue {
    public static void main(String[] args) {
        
        Person person = new Person("DaeSik");
        System.out.println(person.name);
        check(person);
        System.out.println(person.name);
    }
    
    public static void check(Person p) {
        p.name = "Not Daesik";
    }
}
 
class Person{
    String name;
    
    public Person(String name) {
        this.name = name;
    }
}
cs


위 코드에 대한 결과는 다음과 같습니다.



파라미터로 보낸 person의 name 변수 값이 변경된 것을 볼 수 있습니다.

정말 클래스에 대해서는 Call By Reference와 같은 모습을 보여주네요.


그렇다음 다음 예제는 어떨까요?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class CallByValue {
    public static void main(String[] args) {
        
        Person person = new Person("DaeSik");
        System.out.println(person.name);
        check(person);
        System.out.println(person.name);
    }
    
    public static void check(Person p) {
        p = new Person("Not Daesik");
    }
}
 
class Person{
    String name;
    
    public Person(String name) {
        this.name = name;
    }
}
cs


위에 대한 결과는 어떤 모습일지 보도록 하죠.



DaeSik만 두번 찍히는 걸 볼 수 있습니다.

즉, 참조변수 person이 참조하는 인스턴스에 대한 변화가 전혀 없는 것이죠.

Call By Reference라면 DaeSik과 Not DaeSik이 찍혔겠죠.


그 이유는 Java는 파라미터로 클래스나 배열을 보낼 때, 참조하는 원본 데이터에 대한 주소를 보내는 것이 아닌,

참조변수의 주소를 보내게 됩니다.



위 그림을 보시면 파라미터로 받는 참조 변수 p가 참조하는 값이 실제 메모리에 있는 인스턴스가 아닌, Person person인것을 알 수 있습니다.

그렇기 때문에 p = new Person("Not Daesik")을 하게 되면 참조하던 값이 끊기고 새로운 값을 참조하게 되는거죠.

결국 main 메서드에 있는 Person person에는 아무런 변화도 발생하지 않습니다.


이렇게 Java는 클래스나 배열일 경우에도 메모리에 있는 원본 객체에 대한 주소값을 바로 넘기는게 아닌, 원본 객체를 참조하는 주소값을 넘기기에 지금까지 우리가 알고 있는 Call By Reference에 대한 개념이 아니어서 Cal By Reference가 아니라고 합니다.


즉, Java는 모든 순간에서 Call By Value다.



'JAVA' 카테고리의 다른 글

Comparable과 Comparator를 이용한 Class Sort  (1) 2019.03.31