● 자바의 정석 예제를 통하여 call by value를 알아보자
● Call By Value란?
자바, C언어 등은 함수에 매개변수값을 전달할 때 Call By Value라는 방식을 사용한다.
(C++은 참조연산자 '&' 가 있어서 call by reference를 지원한다.)
좀 더 쉽게 말하면 '값'을 복사해서 전달하는 방식을 사용하는데 이것이 바로 Call By Value 라고 한다.
먼저 아래 예제를 한번 같이 살펴보고 그 결과를 예측해보자
class Data {int x;}
public class PrimitiveParamEx {
public static void main(String[] args) {
Data d =new Data();
d.x=10;
System.out.println("main() : x = "+d.x);
change(d.x);
System.out.println("chanege() : x="+d.x);
}
static void change(int x) {
x = 1000;
System.out.println("chanege() : x ="+x);
}
}
Answer↓
main() : x = 10
chanege() : x =1000
chanege() : x=10
우리는 change 메서드를 이용해서 d.x의 값을 받아서 1000으로 바꾸어 주었는데 왜 마지막엔 출력 값이 10으로 나올까? 이 예제가 이해가 어렵다면 그것은 바로 Call By Value 방식을 이해를 못한 것이다. change에서 받은 것은 d.x의 복사 값이다. d.x는 int로써, 우리가 익히 알고 있는 기본형 타입 8가지 중 하나이다. 이 기본 타입은 실제 값을 할당하는 데이터 타입을 의미하며, 이 '값'을 복사해서 가져오는 것이기 때문에 해당 값의 원본을 변경하진 못한다. 결과적으로 change메서드는 '복사 값'을 1000으로 바꾸어준 후 호출 스택(call stack)에서 사라져 버린다. 또한 원본 d.x 에도 영향을 미치지 못한다.
다음 예제를 살펴보자 그리고 똑같이 그 결과를 예측해보자
public class ReferenceParamEx {
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("main(): x ="+d.x);
change(d);
System.out.println("main(): x ="+d.x);
}
static void change(Data d) {
d.x = 1000;
System.out.println("chanege() : x ="+d.x);
}
}
Answer↓
main(): x =10
chanege() : x =1000
main(): x =1000
처음의 예제와 달라진 점을 살펴보면 change의 매개변수가 참조 변수이다. 참조 타입 변수의 경우 실제 값의 주소를 할당하는 데이터 타입을 의미하며, '값의 주소'를 복사해서 가져오기 때문에 해당 값의 원본을 변경하는 것이 가능하다. 처음 예제는 d.x값을 복사해서 넘겨줬다면 이번엔 참조 변수의 '값', 즉 주소(d)를 복사해서 넘겨주었다. change메서드는 그 주소를 참조해서 10이 저장된 곳에 접근하여 1000을 저장해주고 난 뒤 호출 스택에서 사라진다. 첫 번째 예제와는 달리 주소 값을 받아서 원본 값에 접근하여 값을 바꿔준 것이다.
※ CAUTION ※
다음 예제의 결과를 예측해보자
public class Caution {
public static void change(String str) {
str += "456";
}
public static void main(String[] args) {
String str = "ABC123";
System.out.println(str);
change(str);
System.out.println("After change:" + str);
}
}
Answer↓
ABC123
After change:ABC123
str도 참조 변수인데 왜 이번엔 값을 바꾸지 못한 것일까?
이 예제를 이해 못한 것은 사실 call by value를 이해하지못했다기보다는 String 클래스의 '+' 연산자의 작동방법을 모르는 것이다. 위에서도 말했듯 기본형 타입(primitive type)은 함수를 통해서 절대 원본을 바꿀 수가 없다 바로 call by value 이기 때문이다. 그리고 이 기본형 타입과 함께 String 타입도 함수를 통해 절대 원본을 바꿀 수가 없는 타입이다. String의 작동방법을 알아보자면
String str = "ABC123" 은 주소가 0x100이다.
change 메서드를 통하여 str+="456"을 거치면 새로운 문자열 "ABC123456"을 만들고
str이 이젠 새로운 주소 0x200을 가리키게 된다. 반면 main 메서드의 str은 여전히 0x100을 가리키고 있다.
change 메서드의 실행이 끝나면 0x200 주소 값을 가진 str메서드는 호출영역에서 사라지고 "ABC123456" 도 가비지 컬렉터에 의해 사라지게 된다.
정리하자면 String은 + 연산하여 나온 결과를 새로운 주소값을 할당하여 저장하는 작동방식을 지니고 있어서 함수에 아무리 주소값을 넘겨줘도 바꿀 수가 없다.
함수 호출을 통해 원본을 바꾸려면, 주소 값을 타고 연산 조작을 할 수 있는 참조 타입이어야 한다. String이 독특한 케이스인것이다.
(예를 들어 index 연산을 할 수 있는 배열, 멤버 접근 연산자 "."를 사용할 수 있는 멤버 변수 or함수를 가지고 있는 클래스 이 예시들은 본인도 아직 제대로 이해 못함 추후 이해가 되면 내용 추가)
정리하자면 자바는 Call by value방식이 기본이고 Call by reference 가 아닌,
주소 값을 넘겨줘서 원본값이 변경이 되었다 -> 주소값을 복사해서 넘겨준 call by value-reference 방식
Key Point는 call by value를 이해하여, 주소 값을 이용해서 내가 원하는 연산 및 조작을 할 수 있는 능력이다.
'Java > Java Study' 카테고리의 다른 글
[객체지향] 다형성, Polymorphism - Part1 (0) | 2021.04.26 |
---|---|
new 연산자 와 객체생성에 대하여 (0) | 2021.04.24 |
[객체지향] 클래스, 객체, 인스턴스 (0) | 2021.04.12 |
[객체지향] 객체지향 프로그래밍 (6/2일 추가내용 + 다형성) (0) | 2021.04.12 |
java 스터디 2주차 (0) | 2021.01.21 |