Java) Call By Value / Call By Reference

박동규·2023년 5월 9일
0

보통 java 서적을 보면,
객체는 Call By Reference / 원시값은 Call by Value 방식으로 복사가 이루어진다 서술되어 있다.

하지만 이는 독자의 이해를 돕기 위한 설명이고
실제 java에선 Call By Value 개념밖에 존재하지 않는다.

1. 원시값의 복사

public static void main (String[] args) {
	String name1 = "aa";
	String name2 = "bb";
    System.out.println("before call name1 : " + name1 + ", name2 : " + name2);
	test(name1, name2);
    System.out.println("after call name1 : " + name1 + ", name2 : " + name2);
}

public void test(String name1, String name2) {
	name1 = "cc";
    name2 = "dd";
    System.out.println("inner call name1 : " + name1 + ", name2 : " + name2);
}

--- console

before call name1 : aa, name2 : bb
inner call name1 : cc, name2 : dd
after call name1 : aa, name2 : bb

원시값으로 선언된 변수는, stack 영역에 값과 함께 저장된다. 그렇기 때문에 변수를 복사한 변수를 만들고, 복사한 변수를 변경 하더라도 원본 값이 변경되지 않는다.

2. 객체의 복사

public static void main (String[] args) {
	Person A = new Person();
	eatFood(A);
}

실제 내부 동작을 살펴보면

  1. Person A A 라는 지역 변수가 생성되고, Stack 영역에 저장된다. (main 메서드의 Function Frame 내부 지역 변수로 A 저장)
  2. new Person(); Heap 영역에 이름없는 Person 객체가 저장된다.
  3. Person A = new Person(); 지역 변수 A의 포인터가 Heap 영역의 Person 객체를 가리킨다.
  4. eatFood(A) 전달 파라미터로 main 메서드의 지역 변수를 사용했으나 Function Frame 으로 추가된 eatFood 내부에도 A를 저장해야 하므로, 변수 A를 복사하게 된다. 원본 변수 A의 포인터는 Person 객체를 가리키고 있었기에 복사한 A 또한 동일한 포인터를 갖게 된다.
  1. 의 과정을 보통 Call By Reference 라고 지칭한다.

하지만 실제 내부적으로 돌아가는 코드는 객체를 가리키는 변수 그 자체를 복사하는 것이므로, 객체의 복사 또한 Call By Value가 일어나게 된다.

  • 원시값은 변수와 함께 데이터의 값을 복사하는 것이고
  • 객체는 변수와 함께 데이터를 가리키는 포인터를 복사하는 것이다.

객체의 원본 변수와 복사한 변수는 모두 동일한 1개의 객체를 가리키는 포인터를 가지고 있기 때문에

eatFood() 메서드 내부에서 복사한 변수의 참조값인 객체 자체를 변경하게 되면 원본 변수의 값 또한 변경되는 것처럼 보이는 것이고

이 개념을 쉽게 이해하기 위해 Call By Reference라는 명칭으로 부르는 것이다.

0개의 댓글