개요
개발에 대한 글은 정말 오랜만에 적는 것 같다, 이전 글에서도 언급한 대로 다시 초심자의 마음으로 돌아가서 공부를 해보려고 한다.
나는 정말 많은 분야에 대해 매우 얕게 알고 있지만 내 본 진영인 JVM에 대해서는 더 깊게 공부하고 싶은 마음이 들어서 이 글도 적는다.
자바는 pass by value이다
아마 이 글을 읽으시는 분들이라면 둘의 차이는 기본적으로 알고 있을거라고 생각한다, 만약 모른다면 AI에게 간단하게 물어보고 다시 읽자.
사람들과 말해보면 다양한 의견이 나온다, '원시 타입인지 참조 타입인지에 따라 다르다', '모두 pass by reference' 등..
원시 자료형의 경우
아마 원시 자료형에 대한 정답은 다들 이해하기 쉽고 명확할 것 이라고 생각한다, 아래 코드 하나로 설명이 된다.
public void change(int num) {
num = 100;
}
int x = 5;
change(x);
System.out.println(x); // x는 여전히 5이다
매개변수로 넘겨줄 때 값을 복사해서 넘겨주고 원본값에는 영향 받지 않는다.
참고 자료형의 경우
이제 사람들이 여기서 헷갈리게 된다, 아래 코드를 한번 보자
public void changeName(User user) {
user.name = "홍길동";
}
User u = new User("아무개");
changeName(u);
System.out.println(u.name); // 홍길동
이 코드를 보게 되면 사람들은 "어? 원본에 영향을 받았네? 아니 이거 참조가 전달된거잖아요!" 라고 하게 된다. 아래 코드를 또 봐보자
public void changeUser(User user) {
user = new User("새 객체"); // 새로운 객체 설정
}
User u = new User("아무개");
changeUser(u);
System.out.println(u.name); // 아무개
엇, 이렇게 하면 원본인 u 객체에는 아무런 영향을 끼치지 않는다.
여기서 머리 아프겠지만 pass by value와 pass by reference 의 원론적인 의미에 대해서 고민해 봐야 한다.
pass by value를 값을 복사해서 넘긴다는 뜻이다, '값'. 참조 자료형을 사용할 때 이 '값'은 무엇일까?
이 '값'은 사실상 포인터다, heap 영역에 객체가 할당된 메모리 주소를 가르킨다는 것이다. 아래 코드로 한번 풀어봤다
User u = new User("아무개"); // 이 동작을 하게 되면 어떤 일이 일어나느냐?
new User("아무개"); //를 heap 메모리 공간에 할당하고 저장된 메모리 주소를 받는다 예: 0x7ffcd2b8c9c4
User u = 0x7ffcd2b8c9c4 // u라는 변수는 그저 힙 공간의 메모리 주소를 받는것이다
public void changeName(User user) {
//user = 0x7ffcd2b8c9c4 user는 사실상 메모리 주소이다, 그리고 함수를 호출 할 때 복사본을 넘긴거다
user = new User("hi"); // 새로운 0x564e3f5b9000 주소가 생기고 user의 값을 바꿨다
}
changeName(u);
System.out.println(u.name); // 여전히 아무개라고 나온다 왜?
// 참조 자료형의 메모리 주소 '값'을 복사해서 넘긴것이기 때문에
// 함수 안에서의 0x7ffcd2b8c9c4 -> 0x564e3f5b9000가 바뀐것일 뿐
// 여전히 u가 참조하고 있는 메모리 값은 0x7ffcd2b8c9c4이다
// 그리고 0x7ffcd2b8c9c4이 참고하고 있는 객체는 new User("아무개") 였기 때문에 u.name은 아무개다
위 논리에 따라서 자바는 참조 자료형의 경우 조차 pass by value, 즉 값을 복사해서 넘기는 것이다.
만약에 자바가 pass by reference였다면 아래와 같이 동작해야 한다.
User u = new User("아무개");
new User("아무개"); //를 heap 메모리 공간에 할당하고 저장된 메모리 주소를 받는다 예: 0x7ffcd2b8c9c4
User u = 0x7ffcd2b8c9c4;
public void changeName(User user) {
user = new User("hi"); // 새로운 0x564e3f5b9000 주소가 생기고 u의 값을 바꿔야 한다, 왜냐면 값 자체를 참조하고 있기 때문이다
}
changeName(u);
System.out.println(u.name); // hi라고 나온다
// changeName을 호출할 때 0x7ffcd2b8c9c4 라는 메모리 주소를 저장하는 값의 '참조'를 넘겼기 때문에
// 함수 안에서의 0x7ffcd2b8c9c4 -> 0x564e3f5b9000로 바뀌면 함수 밖의 u도 0x564e3f5b9000로 바뀐다
// 그러면 0x564e3f5b9000의 메모리 주소는 hi를 가르키고 있기 때문에 u.name에서 hi가 출력된다
하지만 자바는 이렇게 동작하지 않는다, 그래서 원시타입, 참조타입 모두 pass by value이다
마무리하며
벌써 자바라는 언어를 중학교 시절부터 포함하면 7년 정도 다루고 있다, 아직도 이런 부분에 대해서 공부하지 못한게 좀 부끄럽다.
지금까지는 자바를 이용해서 내 세상을 만들고 구현하는것에 집중했다면 이제는 내가 쓰는 언어가 무엇인지에 대해 본질적으로 탐색하고 싶어지는 욕심이 생겼다.
또한 이번 개념을 이해하는데 해킹하던 시절 배웠던 C언어와 메모리 구조등이 도움이 많이 되었다, 어떤 분야의 지식이든 편식하지 말고 학습하는것도 중요하다는 생각이 들었다.
'개발 공부 일기장 > Java Develop' 카테고리의 다른 글
| SpringBoot에서 수많은 AI 프롬프트 우아하게 관리하기 (3) | 2025.08.05 |
|---|---|
| Spring의 Response Entity 꼭 사용해야 하는가? (0) | 2024.09.10 |
| SpringBoot Test, 숫자로 테스트 메소드 실행 순서 정하기 (0) | 2023.02.21 |
| SpringBoot Junit을 이용한 RestAPI 테스트 코드 작성 (0) | 2023.02.20 |
