일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 단기개발자코스
- 개발자 취업
- 디자인 패턴
- 코딩테스트 준비
- 프로그래머스 이중우선순위큐
- 파이썬
- DesignPattern
- 항해99
- 개발자부트캠프추천
- 프로그래머스
- JavaScript
- infcon 2024
- spring batch 5.0
- 빈 조회 2개 이상
- Python
- jwttoken
- 취업리부트코스
- jwt
- 1주일회고
- 전략패턴 #StrategyPattern #디자인패턴
- Spring multimodule
- 99클럽
- KPT회고
- TiL
- 구글 OAuth login
- 커스텀 헤더
- 인프콘 2024
- @FeignClient
- 디자인패턴
- 빈 충돌
- Today
- Total
m1ndy5's coding blog
Call by Value / Call by Reference in Java 본문
자바의 Call by Value / Call by Reference
함수의 매개변수에서 값을 복사하느냐 주소값을 참조하느냐의 차이이다.
자바의 데이터형은 크게 두가지로 나뉜다.
기본형(primitive type) - Boolean Type(boolean), Numeric Type(short, int, long, float, double, char)
참조형(reference type) - Class Type, Interface Type, Array Type, Enum Type, 기본형을 제외한 모든 것들
이 때 메서드의 파라미터에 원시값(primitive type)을 전달하는 것과 객체(reference type)를 전달하는 것에 동작 차이가 있다.
어떻게 이런 차이가 난 것일까?
Call by Value / Reference 과정
public class main
{
public static void main(String[] args)
{
Sample sample = new Sample();
int var = 1; // primitive 타입 변수 int
int[] arr = { 1 }; // reference 타입 변수 int[] 배열
// 변수 자체를 보냄 (call by value)
add_value(var);
System.out.println(var); // 1 : 값 변화가 없음
// 배열 자체를 보냄 (call by reference)
add_reference(arr);
System.out.println(arr[0]); // 101 : 값이 변화함
}
static void add_value(int var_arg) {
var_arg += 100;
}
static void add_reference(int[] arr_arg) {
arr_arg[0] += 100;
}
}
이 샘플 코드로 예시를 확인해보자
main함수가 실행되면
int var = 1; // primitive 타입 변수 int
int[] arr = { 1 }; // reference 타입 변수 int[] 배열
변수들이 메모리 영역에 저장되기 시작하는데 이 때 스택 영역과 힙 영역에 대해 알아둬야한다!!
스택 영역
- 메서드 내에서 정의하는 기본 자료형에 해당하는 지역변수의 데이터 값이 저장되는 공간
- 메서드가 호출될 때 스택 영역에 스택 프레임이 생기고 그 안에 메서드를 호출
- 메서드가 호출될 때 메모리에 할당되고 종료되면 메모리에서 사라짐
- LIFO의 특성을 가짐
* 스택 프레임 : 하나의 메서드에 필요한 메모리 덩어리, 하나의 메서드 당 하나의 스택 프레임이 필요하며 메서드를 호출하기 직전 스택프레임을 자바 Stack에 생성한 후 메서드를 호출함, 스택 프레임에 쌓이는 데이터는 메서드의 매개변수, 지역변수, 리턴값 등이 있음, 메서드 호출 범위가 종료되면 스택에서 제거됨
힙 영역
- JVM이 관리하는 프로그램 상에서 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 영역
- 참조형 데이터 타입을 갖는 객체, 배열 등이 저장 되는 공간
- Heap 영역에 있는 오브젝트들을 가리키는 레퍼런스 변수는 스택에 적재
- Heap 영역은 Stack 영역과 다르게 보관되는 메모리가 호출이 끝나더라도 삭제되지 않고 어떤 참조 변수도 인스턴스를 참조하지 않게 된다면, GC에 의해 메모리에서 청소됨
- 스택은 스레드 갯수마다 각각 생성되지만 힙은 단 하나의 힙 영역만 존재
위의 설명에 따라서 main 메서드 실행시에 스택 프레임이 생기게 되고 그 안에는 원시자료형인 var, 참조자료형인 arr이 저장되어 있다.
이 때 참조자료형인 arr은 주소값을 가지고 있게 되고 이 주소값은 힙 영역에 있는 값을 가리키고 있다.
// 변수 자체를 보냄 (call by value)
add_value(var);
System.out.println(var); // 1 : 값 변화가 없음
add _value 메서드를 실행시키면 add_value 메서드 스택 프레임이 생성되고 해당 메서드의 매개변수, 변수들이 저장된다.
이 때 var_arg는 원시 타입이기 때문에 힙영역을 참조하지는 않는다.
이후 add_value 메서드가 종료됨에 따라 스택 프레임은 날라간다.
이렇듯 스택 프레임 내에서 값이 변하는 것은 메서드가 종료됨에 따라 날라가기 때문에 기존 메인 스택 프레임의 값에 변화를 주지 못한다.
// 배열 자체를 보냄 (call by reference)
add_reference(arr);
System.out.println(arr[0]); // 101 : 값이 변화함
add_reference 메서드 같은 경우 매개변수가 참조자료형이기 때문에 스택프레임에서는 힙메모리에 저장되어 있는 배열의 주소값을 가지고 있게 된다.
이 때 이 주소값은 메인 메서드에서 넘겨받은 arr과 똑같은 주소값이다.
따라서 add_reference 메서드 내에서 주소값에 해당하는 배열 안에서 값의 변화가 일어나게 된다면 이는 그대로 heap 메모리에 반영되게 되고 add_reference 스택 프레임이 사라지고 나서도
메인 스택 프레임에서 변화가 일어난 배열을 참조하고 있기 때문에 메서드 안에서의 변경이 메인 메서드의 변수에 영향을 주게 된다.
자바에는 Call by Reference가 없다고?
Java의 Call by Reference는 존재하지 않는다.
기껏 다 설명했는데 왜 존재하지 않는다고 말하는거야?? 한다면
그 이유는 C언어와 달리 자바에서는 개발자가 직접 메모리 주소에 접근할 수 없기 때문이다.
(C언어는 포인터를 사용해 그대로 주소를 통해 메모리 참조 가능)
결론
자바의 파라미터는 call by value로서만 동작되며, 원시값이 복사되냐 주소값이 복사되냐의 차이가 있을 뿐이다.
'CS Study' 카테고리의 다른 글
Garbage Collector (1) | 2024.03.07 |
---|---|
Java의 메모리 영역 (0) | 2024.03.07 |
JVM, JRE, JDK & 자바 프로그램의 실행 과정 (0) | 2024.03.07 |
영속성 컨텍스트 (0) | 2024.03.06 |
JPA 도입 시 고려해 볼 사항 (0) | 2024.03.06 |