콜바이 밸류와 콜바이 래퍼런스의 기본 개념
프로그래밍 언어에서 함수나 메서드를 호출할 때 인자 전달 방식에는 크게 두 가지가 있다.
- 콜바이 밸류(Call By Value)
- 콜바이 래퍼런스(Call By Reference)
이 두 방식은 인자를 전달하는 메커니즘의 차이를 가지며, 이로 인해 함수 내부에서 인자의 값을 변경했을 때 외부에 미치는 영향이 달라진다.
1. 콜바이 밸류(Call By Value)
콜바이 벨로는 값에 의한 호출로, 함수을 호출할 때 인자의 값을 값을 복사하여 함수의 매개변수로 전달하는 방식이다. 따라서 함수 내부에서 값을 변경해도 원본 데이터에는 영향을 미치지 않는다. 이로 인해 함수 호출 후에도 원본 값이 유지된다.
이러한 특성 덕분에 부작용을 최소화할 수 있다.
2. 콜바이 래퍼런스(Call By Reference)
콜바이 래퍼런스 방식에서는 함수를 호촐할 때 인자의 메모리 주소를 전달한다. 따라서 함수 내부에서 매개변수의 값을 변경하면, 그 변경이 원본 인자에도 반영된다.
메모리 주소를 통해 직접 원본 데이터에 접근하는 방식이기 때문에, 함수 내부에서의 변경이 원본 데이터에도 영향을 미치게 된다. 이 방식에 경우 데이터를 직접 조작해야 하는 경우에 유용하다.
자바에서의 관점
자바에서의 콜바이 밸루와 래퍼런스를 나타내는 말은 다음과 같이 정리할 수 있다.
Java는 C, C++처럼 개발자가 직접 메모리 포인터를 관리하는 언어가 아니다. 따라서 Java는 항상 Call By Value 방식만 사용한다. 다만, 객체를 전달할 경우 참조값(Reference)이 복사되어 전달되므로 Call By Reference처럼 동작하는 것처럼 보일 수 있다.
자바에서 기본형 타입(Primitive Type)과 참조형 타입(Reference Type)에서 함수 동작을 통해 해당 문구를 분석해보자.
2025.01.04 - [Language/Java] - [Java] 기본형 vs 참조형
[Java] 기본형 vs 참조형
기본형과 참조형변수의 데이터 타입을 크게 나눠보면 기본형과 참조형이 있다.기본형(Primitive Type): `int`, `long`, `double`, `boolean`처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입을 기본형
jh7722.tistory.com
1. 기본형 타입(Primitive Type)
기본형 타입의 변수 `a`를 `modify(int num)`에 매개변수로 활용했을 시, 원본 값에 변화를 보는 예시이다.
public class Example {
public static void modify(int num) {
num = 10; // 값 변경
}
public static void main(String[] args) {
int a = 5;
modify(a);
System.out.println(a); // 여전히 5
}
}
출력 결과를 보면 `a`의 값이 변하지 않는다.
이는 "Java는 항상 Call By Value 방식만 사용한다."는 개념을 잘 보여주는 예시다.
기본형 타입을 매개변수로 전달할 때 원본 값이 그대로 넘어가는 것이 아니라, 복사된 값이 전달되기 때문이다.
따라서 함수 내부에서 매개변수를 변경해도 원본 값에는 아무런 영향을 주지 않는다.
즉, 기본형 타입을 사용할 때는 원본 값이 변경될 가능성을 고려할 필요가 없다.
2. 참조형 타입(Reference Type)
자바에서 참조형(Reference Type) 변수를 함수의 매개변수로 전달하면, 객체의 참조값(메모리 주소)이 복사된다.
따라서 함수 내부에서 객체의 속성이 변경하면 원본 객체에도 영향을 미친다.
class Example {
int value;
Example(int value) {
this.value = value;
}
}
public class ReferenceExample {
public static void modify(Example obj) {
obj.value = 10; // 원본 객체의 필드 값 변경
}
public static void main(String[] args) {
Example example = new Example(5);
modify(example);
System.out.println(example.value); // 출력: 10 (원본 객체의 값도 변경됨)
}
}
출력 결과를 보면, `example` 객체의 `value` 값이 변경된 것을 알 수 있다.
즉, 메모리 주소를 복사하여 전달하기 때문에 Call By Reference처럼 보이는 동작을 한다.
다음은 new 키워드를 활용하여 새로운 객체를 생성하는 경우이다.
class Example {
int value;
Example(int value) {
this.value = value;
}
}
public class ReferenceExample {
public static void modify(Example obj) {
Example a = new Example(10);
obj = a // 새로운 객체를 생성하여 obj에 할당
}
public static void main(String[] args) {
Example example = new Example(5);
modify(example);
System.out.println(example.value); // 출력: 5 (원본 객체는 변경되지 않음)
}
}
출력 결과를 보면, `example` 객체의 값이 변경되지 않았다. 만약 Call by reference라고 한다면 메소드 호출 이 후 원본 값에 변화가 있어야 한다.
하지만 참조값이 바뀐 것이 아니기 때문에 `obj`, `a`는 `modify()` 메소드 안에서만 사용되고 가비지컬렉터의 수집 대상이 된다.
Java에서는 객체의 참조값(메모리 주소)만 복사되어 전달된다. 따라서 함수 내부에서 참조 변수를 변경해도 원본 객체와의 연결이 끊어질 뿐, 원본 객체 자체는 영향을 받지 않는다.
즉, 참조형에 경우 Call by reference처럼 동작해보일 순 있지만, 결국엔 자바에 값 복사에 의해 동작되는 방식이므로 자바는 향상 Call By Value로 동작하게 된다.
'Language > Java' 카테고리의 다른 글
[Java] Java8 메모리 구조 변화 (PermGen -> Metaspace) (1) | 2025.02.19 |
---|---|
[Java] 스레드와 자바 메모리의 관계 (0) | 2025.02.05 |
[Java] 제네릭(Generic) (1) | 2025.01.31 |
[Java] 자바 예외 처리 - 예외 계층, 체크 예외, 언체크 예외, 예외의 규칙 (0) | 2025.01.31 |
[Java] Class 클래스 (0) | 2025.01.30 |