(이 글은 이전에 제 티스토리 블로그에 업로드했었던 글을 가져온 것입니다.)
평소에 자바를 다룰 기회가 많지도 않았고, 막상 다루더라도 학부의 기본적인 과제를 수행하기 위해 자바를 사용했다.
문법 조금 안다고 안일하게 '이정도면 되겠지', '다음에 제대로 공부해야지'라는 안좋은 습관이 있고, 이는 오직 구현에만 초점을 맞추게 된 엉망코드를 만들어 내기의 지름길이 되었다.
이번에 운좋게 합격한 프로그래머스 데브코스 백엔드 과정을 수행하기 위해서는 자바는 기본적으로 자유롭게 다뤄야 된다는 생각 하에, 기본적인 지식과 알던것들은 가볍게 다시 보고, 몰랐던 부분들에 대해 집중적으로 공부하려고 한다.(비록 학교 시험기간이지만 ..)
또한 기록하는 것을 상당히 (많이) 귀찮아 하는 성격이지만, 나를 위해서라도 성격을 무시하고 정리하는 습관은 무조건 필요하다고 생각되기에 꾸준히 블로그에 정리하는 습관을 들이려고 한다.
알아 둘 점
자바는 변수를 선언할 때, 원시타입이든, 참조타입이든 Stack 영역에 할당이 된다.
이때 참조타입의 변수는 Stack영역에 할당되지만 실제 객체가 저장되어 있는 Heap영역의 주소값을 가리키고 있다.
함수 파라미터 역시 동일하게 Stack영역에 할당된다.
원시타입이면, Stack영역에 할당만 하고, 참조타입이면 Stack영역에 할당 이후 인자로 넘겨주었던 원래 객체의 주소를 가리킨다.
Call by Value, Call by Reference
1. Call by Value
메소드를 호출할 때, 인자에 들어갈 변수의 '값'만 넘겨주는 함수 호출 방식이다.
자바의 메소드 호출 방식
여기까지 봤다면, "자바에서 객체를 파라미터로 넘겨주어 객체 속성값을 변경할 수 있으므로, 자바는 Call by Reference를 지원하지 않나?" 라는 생각을 할 수 있지만, 실제로는 Call by Value만 지원한다고 한다.
코드를 살펴보며 이해해 보자.
원시타입 파라미터
public static void callByValue(int age) {
age = 10;
}
public static void main(String[] args) {
int age = 20;
System.out.println("before age = " + age);
callByValue(age);
System.out.println("after age = " + age);
}
결과 :
before age = 20
after age = 20
지극히 기본적인 Call by Value방식이다. 인자로 전달받은 age의 값을 변경해 보지만, 이는 main에서 전달받은 변수 age의 주소값이 담기지 않고, 그저 Stack상에서 새롭게 생겨난 age변수(함수 인자로 전달받아서 새로 할당된 변수)의 값을 바꾼 셈이다. 따라서 main에서의 결괏값은 10이 아닌, 20이 나온다.
참조타입 파라미터
public class Person {
int age;
public Person(int age) {
this.age = age;
}
}
public static void callByValue2(Person person) {
person.age = 20;
}
public static void main(String[] args) {
Person person = new Person(10);
System.out.println("before age = " + person.age);
callByValue2(person);
System.out.println("after age = " + person.age);
}
결과 :
before age = 10
after age = 20
callByValue2 메소드가 호출되면 기본적으로 새로운 변수가 Stack영역에 할당되고, 인자로 넘겨준 CallByRef 객체의 주소값을 가리킨다. 따라서 함수 내에서 새롭게 생겨난 person변수는 실제 인자로 전달해준 객체의 주소값을 가리키고 있으므로, 메소드 내에서 멤버변수를 수정해도 원래 객체의 멤버변수에까지 결과가 미치는 것이다.