JAVA

[Java] Call by Value 와 Call by Reference

경딩 2024. 10. 21. 12:57

Call By Value와 Call By Reference

  • Call By Value (값에 의한 호출) 
    • 인자로 받은 값을 복사하여 처리하는 방식입니다.
    • 장점 - 값을 복사하여 처리하기 때문에 원래의 값이 보존됩니다.
    • 단점 - 복사하기 때문에 메모리 사용량이 증가합니다.
  • Call By Reference(참조에 의한 호출) 
    • 인자로 받은 값의 주소를 참조하여 직접 저장해 값에 영향을 주는 방식입니다. 
    • 장점 - 복사하지 않고 직접 참조가 빠릅니다.
    • 단점 - 직접 참조를 하기에 원래의 값이 영향을 받는다.

 

그럼 Java에서는 어느 부분이 call by value이고 어느 부분이 call by reference에 해당하나요?

  • Java의 기본적으로 모든 전달 방식은 Call By Value입니다.
  • 참조형의 경우 객체의 '주소값'을 매개변수로 전달하니 call by reference 가 아니냐는 의문을 가질 수 있지만,
  • 정확하게 말하면 '주소값'이 아니라 '주소를 가리키는 참고값'입니다.
  • 또한, 주소값 자체를 '복사 없이' 인자로 전달하는 게 아니라 자기 자신이 갖고 있는 값을 복사해서 전달합니다.
  • 결국 기본형 변수나 참조형 변수 모두 자기 자신이 갖고 있는 값을 복사해서 전달하기 때문에 call by value입니다.

 

자바의 Call By Value 동작방식

자바의 데이터 타입은 원시형과 원시형을 제외한 참조형만이 존재한다.

  • 원시 타입(primitive type) -  Numeric Type (byte, short, int, long, float, double, char), Boolean Type(boolean)
  • 참조 타입(reference type) - Class Type, Interface Type, Array Type, Enum Type 등등

그래서 메서드 파라미터로 원시 타입을 전달하는 것과 참조 타입을 전달하는 것에는 동작방식 차이가 있다.

 

원시타입의 값 전달 원리

package hello.core.callByValue;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class PassByValueTest {
    
    @Test
    void addInt() {
        int x = 10;
        add(x);
        assertThat(x).isEqualTo(10);
    }

    private void add(int num) {
        num++;
    }
}

  • 자바에서는 원시 타입은 스택 영역에 할당됩니다.

 

  • 따라서 다음과 같이 X 가 statck 영역에 할당되게 됩니다.
  • 그다음으로는 add 메서드를 호출하고 있습니다.
  • 자바는 값을 복사하여 전달하기 때문에 add 함수에서 사용될 변수 num 이 x를 바탕으로 복사됩니다,
  • 그리고 num 값을 증가시키므로 메모리에는 다음과 같이 11 이 남아있게 됩니다.
  • 복사된 값이므로 x 변수는 아무런 영향을 받지 않습니다.
  • 따라서 원시 타입의 전달은 값을 복사해서 전달하는 Call By Value 방식입니다.

 

참조타입의 값 전달 원리

    @Test
    void addArray() {
        String[] strings = new String[2]; // 주소 : 0x001
        strings[0] = "Hello";
        add(strings);
        assertThat(strings[0]).isEqualTo("Java"); 
    }

    private void add(String[] arrays) {
        arrays[0] = "Java"; // 주소 : 0x001
    }

 



  • 원시타입 변수는 Stack 영역에 생성되고,  참조 타입은 Heap 영역에 할당됩니다.
  • Stack 영역에 있는 변수가 Heap 영역에 있는 객체를 바라보고 있는 형태입니다.

  • 변수의 참조(주소) 값을 복사해서 전달하는 addArray() 영역과 add() 영역의 변수들은 동일한 객체 주소 (0x001)을 바라보도 있습니다.
  • arrays는 변수는 strings에서 복사되어 생성되므로 string와 별개로 존재합니다.
  • 하지만 두 변수 모두 동일한 참조를 가리키기 때문에 add 함수에서 arrays 값을 변경하며 straings 변수 또한 영향을 받게 됩니다.

 

결국 자바는 항상 Call By Value 방식으로 데이터를 전달하고, 핵심은 호출자 변수와 수신자 파라미터는 Stack 영역 내에서 각각 독립적으로 존재하는 다른 변수라는 것이다.

 

출처: https://dev-coco.tistory.com/189 [슬기로운 개발생활:티스토리]

 

'JAVA' 카테고리의 다른 글

[JAVA] staic 과 final  (1) 2024.10.29
== 와 equals 차이 , hashcode  (0) 2024.10.24
[자바의 신] 정리해봅시다 [1장~ 10장]  (0) 2024.10.19
[JAVA] ORM 이란? MyBatis 와 JPA 차이  (4) 2024.10.11
[JAVA] 자바 버전과 특징 8 ,11  (0) 2024.10.10