우리가 함수나 메서드를 호출할때 방식은 크게 2가지의 방법이 있다.
Call by Value, Call by Reference
그렇다면 2가지에 대해서 비교해보자
Call by Value
public class CallByValueExample {
public static void addTen(int number) {
number = number + 10; // 매개변수의 값 변경
System.out.println("Inside addTen: " + number);
}
public static void main(String[] args) {
int a = 5;
addTen(a); // a의 값은 여전히 5
System.out.println("In main after addTen: " + a);
}
}
- 정의 - Call by value 방식에서는 함수에 인자를 전달할 때, 인자의 실제 값(value)이 복사되어 함수의 매개변수로 전달됩니다.
- 동작 방식
- 함수가 호출될 때, 인자의 값이 새로운 메모리 위치에 복사되며 함수 내에서 매개변수의 값을 변경해도, 원래 인자의 값은 불변.
- 특징
- 함수 내에서 매개변수의 값을 변경해도 원본 데이터에는 영향을 미치지 않아 부수 효과(side effect)가 없다
- 큰 데이터를 복사할 때 성능 저하가 발생우려
- 함수 안에서 인자 값이 변경되더라도, 외부 변수 값은 변경되지 않는다.
- addTen(a);를 하여도 기존의 a는 변경되지 않는다
Call by Reference
public class CallByValueOfReferenceExample {
static class Number {
int value;
Number(int value) {
this.value = value;
}
}
public static void addTen(Number number) {
number.value += 10; // 객체의 상태 변경
System.out.println("Inside addTen: " + number.value);
number = new Number(30); // 매개변수에 새로운 객체 할당
System.out.println("Inside addTen after new assignment: " + number.value);
}
public static void main(String[] args) {
Number myNumber = new Number(5);
addTen(myNumber); // myNumber 객체의 상태가 변경됨
System.out.println("In main after addTen: " + myNumber.value); // new Number(30) 할당은 영향을 미치지 않음
}
}
- 정의: 함수에 인자를 전달할 때, 인자의 메모리 주소(reference)가 전달됩니다. 즉, 함수는 원본 인자를 직접 참조하게 됩니다.
- 동작 방식: 함수가 호출될 때, 인자의 메모리 주소가 함수의 매개변수로 전달됩니다. 함수 내에서 매개변수를 통해 원본 데이터를 직접 변경할 수 있습니다.
- 특징: 함수 내에서의 변경이 원본 데이터에 직접 반영되므로, 원본 데이터를 쉽게 수정할 수 있습니다. 그러나 이로 인해 부수 효과가 발생할 수 있으며, 원본 데이터를 실수로 변경할 위험이 있습니다.
- addTen(myNumber);를 진행할경우 myNumber의 값이 변경된다.
자바의 경우 call by value 방식을 사용한다.
원본 데이터를 변경할 위험이 줄어들며
하단의 코드는 Call By value를 실제 코드를 비교한 방법이며
callme 함수를 호출한 하여도 원본 객체인 valueTest1의 값이 변경되지 않음을 확인할수있다.
public static void main(String[] args) {
String valueTest1 = new String("abc");
String valueTest2 = valueTest1;
callme(valueTest1);
System.out.println("#3 " + valueTest1.equals("abc")); // true
System.out.println("#4 " + valueTest1.equals("ccc")); // false
System.out.println("#5 " + (valueTest1==valueTest2)); // true
}
static void callme(String str) {
System.out.println("#1 " +str.equals("abc")); // true
str = new String("ccc");
System.out.println("#2 " + str.equals("ccc")); // true
}
안정성과 예측 가능성: "Call by Value"를 사용하면 함수에 전달된 값이나 참조의 복사본을 작업하게 되므로, 원본 데이터가변경될 위험이 줄어든다.
디버깅 용이성: "Call by Value" 방식에서는 함수 호출 시 매개변수의 값이나 참조의 복사본이 생성되기에 이로 인해 함수 내에서 발생하는 변경이 외부에 영향을 미치지 않아, 디버깅 시 변수의 값이 어디에서 변경되었는지 알기가 쉽다.
메모리 관리: Call by Value 방식은 함수 호출이 끝나면 매개변수로 사용된 복사본은 스코프를 벗어나 가비지 컬렉터에 의해 처리되어 메모리 누수의 위험이 줄어든다.
멀티스레드 환경에서의 안정성: Java는 멀티스레드 프로그래밍을 광범위하게 지원하는데 "Call by Value" 방식은 멀티스레딩 환경에서 공유 데이터에 대한 동시 접근으로 인한 RaceCondition을 방지할수 있다.
'JAVA' 카테고리의 다른 글
자바 주니어 질문 100건 (기초) (0) | 2024.11.02 |
---|---|
DocumentBuilderFactory와 예제 (0) | 2024.02.18 |
스레드풀 (0) | 2023.03.07 |
프로세스와 스레드 (0) | 2023.03.07 |
동일성(identity)과 동등성(equality) (0) | 2023.02.26 |