주인장의 프로그래밍 개발 공부방

[Chapter 1 변수] 10. (심화) 참조형 변수의 리터럴 선언 본문

프로그래밍 기본 지식/Chapter 1 변수

[Chapter 1 변수] 10. (심화) 참조형 변수의 리터럴 선언

거신 2019. 5. 12. 21:47

이전 시간에 우리는 참조형 변수의 기본 값이 무엇인지와

변수 초기화를 하는 방법에 대해서 알아봤었다.

참조형 변수에서는 null이라는 새로운 녀석이 등장했는데

null은 말 그대로 진짜 아무런 의미도 가치도 없는 값이라고 했었다.

오늘은 참조형 변수에서 조금은 흥미로운 내용을 알아보려고 한다.

 

목표 : 참조형 변수에 new 생성자가 아닌 리터럴을 그대로 넣을 때 결과가 어떻게 되는지 알 수 있다.

 

1. (심화) 참조형 변수의 리터럴 선언

 

제목이 조금 어려워 보일 수도 있는데

쉽게 풀어보면 참조형 변수를 선언할 때 new 생성자를 사용한 선언이 아니라

리터럴, 즉, 실제 값을 넣어 선언하는 것이다.

 

우리가 기본형 변수를 선언할 때는 당연히

 

int i = 10;

 

과 같이 리터럴을 넣게 되는데

앞서 참조형 변수를 선언할 때는

 

String str = new String();

 

과 같이 new라는 생성자를 사용한다고 배웠었다.

또는 null을 넣어서 기본 값을 넣는다고 배웠는데

여기에서 만약 참조형 변수를 기본형 변수처럼 선언하면 어떻게 될까?

 

String str = "자바";

 

과연 이렇게 코드를 작성하면 오류가 발생할까?

정답은 오류없이 아~~~주 잘 돌아간다.

오! 그렇다면 참조형 변수도 기본형 변수처럼 선언해서 사용해도 된다는 말인가? 그런건가?

그렇다. 가능하다.

하지만 메모리에 저장되는 과정이 달라지기 때문에

이 부분에 대해서는 자세하게 알고 넘어갈 필요가 있다.

 

2.1 (심화)참조형 변수에서 리터럴로 선언 시 달라지는 점 - 1

 

사실 단순히

 

String str = "자바";

 

라는 코드 한 줄만 프로그램 내에 있다면 별 일도 없고

우리가 이렇게 복잡하게 생각해야할 일도 없다.

그런데 문제는 우리가 프로그래밍을 하는데 저 코드가 단 하나만 있을거란 보장을 할 수가 없다는 점이다.

프로그램을 하나 만드는데 몇 백줄, 몇 천줄, 몇 만줄이나 되는 코드가 있는데

고작 저 코드 한 줄만 달랑 있다는게 말이나 되는가?

그래서 좀 더 코드를 추가해서 알아보도록 하자.

 

String str1 = "자바";

String str2 = "자바";

String str3 = new String("자바");

 

이렇게 3줄의 코드를 작성했다.

위의 str1과 str2는 new 생성자를 사용하지 않고 리터럴을 그대로 넣은 것이고

str3은 new 생성자를 사용해 새로운 참조 변수를 생성해 만든 것이다.

조금 어려워 보일 거 같으니 그림으로 한 번 알아보자.

가장 먼저 첫 줄을 실행하면 메모리에서 이러한 과정으로 변수가 생성이 될 것이다.

앞서서 설명한 적이 있기 때문에 자세한 설명은 생략한다.

여기까지는 new 생성자를 사용하든 리터럴을 그대로 넣든 별 차이가 없어 보인다.

그런데 여기까지다.

두 번째 줄을 실행하면 이렇게 된다.

두 번째 줄을 실행하면 참조 변수 str2가 생성이 되는데 어째서인지

str2에도 str1과 똑같은 주소가 저장이 되는 것일까?

이전에 참조형 변수를 선언하는 방법을 알아볼 때

new 생성자를 사용하면 참조 변수를 생성할 때마다 새로운 주소를 할당받는다고 했었다.

 

그렇다면 str2가 새 주소 값이 아니라 str1과 똑같은 주소 값을 저장한 이유가

바로 new 생성자를 사용하지 않았기 때문이라는 것을 어느 정도 유추할 수가 있을 것이다.

일단 그 이유를 알아보기 전에 세 번째 줄까지 실행해보자.

세 번째 줄까지 실행하면 그림처럼 메모리 내부가 바뀌게 된다.

당연히 str3는 new 생성자를 사용해 참조 변수를 선언했기 때문에

Heap영역에 새로운 곳에 "자바"라는 값을 저장하고

그 주소를 str3에 저장하는 것이다.

 

그렇다면 도대체 str2는 어떻게 된 것일까?

 

2.2 (심화)참조형 변수에서 리터럴로 선언 시 달라지는 점

 

참조형 변수는 기본형 변수와는 다르게 주소 값이라는 녀석을 건드리게 되는데

이게 new 생성자가 아닌 리터럴을 그대로 선언하게 되면

다음과 같은 과정을 진행하게 된다.

 

먼저

 

String str1 = "자바";

 

라는 코드가 실행이 되면 우리 눈에는 new 생성자를 사용한 것처럼

과정이 진행되는거 같아 보이겠지만 사실 그렇지 않다.

만약 참조형 변수리터럴이 바로 들어오면 컴퓨터는

일단 Stack영역4byte 크기의 str1이라는 참조 변수를 생성한다.

그리고 Heap영역에 바로 "자바"라는 값을 생성해서 저장하는 것이 아니라

일단 Heap영역을 아주 빠르게 전체를 훑어본다.

지금 Heap영역에 "자바"라는 값을 가진 장소가 있는지 없는지를 검색한다는 뜻이다.

Heap영역 전체를 훑어보고 만약 "자바"라는 값을 가진 장소가 없다면

그제서야 새롭게 주소를 할당하고 "자바"라는 값을 저장하고

그 주소 값을 아까 만들어놨던 str1에 저장하게 되는 것이다.

 

중간에 컴퓨터가 Heap영역을 검색한다는 과정이 추가되게 되는 것이다.

그래서 두 번째 줄인

 

String str2 = "자바";

 

를 실행하게 되면 역시 str1과 마찬가지로 일단 Stack영역에 str2를 생성하고

Heap영역을 전체적으로 훑어보게 된다.

이번에는 아까 str1을 생성할 당시에 할당해 둔 장소가 존재하고 있기 때문에

이 장소를 찾게 되면 이 장소의 주소 값을 str2에 저장하게 되는 것이다.

이러한 과정을 거치기 때문에 str1과 str2에 똑같은 주소 값이 저장되게 되는 것이다.

 

세 번째 줄인

 

String str3 = new String("자바");

 

new 생성자를 사용해 선언한 것이기 때문에

우리가 알고 있는 참조형 변수가 생성되는 과정 그대로 진행된다.

 

분명 이러한 작성법이 장단점이 존재할 것으로 예견되지만

일단 우리는 그런 부분은 생각하지 말고 참조형 변수를 생성할 때는

new 생성자를 사용해서 변수를 생성하는 것을 기본으로 생각하자.

지금 배운 내용들은 언젠가 실전에서 쓰이는 날이 올 수도 있지만

지금은 아 이런 것도 있구나라고 이해하고 알고만 있어도 충분하다고 생각한다.

 

4. (번외) 만약 String 참조 변수에 문자열이 아니라 숫자를 넣으면?

 

굉장히 흥미로운 부분이다.

일단 기본적으로 우리가 알고 있는 지식으로는

String 참조 변수문자'열'을 처리하는 참조 변수라고 배웠다.

그렇다면 문자열이 아닌 숫자를 넣으면 어떻게 될까?

 

정답은 오류 뿜뿜이다.

 

정말 융통성이 없는 것인지 아니면 자기 일에 너무 충실한 것인지

문자열에 사용하는 참조 변수라서 숫자는 사용할 수가 없다.

가령

 

String str1 = 1234;

String str2 = new String(1234);

 

와 같이

" "(큰 따옴표 Double Quotation)없이 숫자만 입력하면 오류가 발생한다.

이유는 간단하다.

숫자는 문자열이 아니니까.

그렇기 때문에 너무나 당연하게도 숫자를 사용하려면

기본형 변수의 정수형, 실수형 타입의 변수들을 사용해야 한다.

또는 저 숫자들에 큰 따옴표를 붙여 문자열처럼 사용하면 된다.

(그렇게 되면 "1234"는 숫자로 인식하지 않고 문자열로 인식하니 수학적 연산이 되지 않는다.)

 

알고보면 의외로 별거 아닌 내용이긴 하지만

알아본다고 해서 손해볼 건 없잖아?

 

5. 마무리

 

참조형 변수new 생성자가 아니라 기본형 변수처럼 리터럴로 바로 선언이 가능하다.

하지만 그렇게 선언하면 new 생성자로 선언하는 것과 다른 과정을 거치기 때문에

다른 두 참조 변수가 같은 주소 값을 저장할 수도 있는 상황이 발생할 수도 있다.

일단은 이러한 것도 있다만 이해하고 있어도 나중에 엄청 도움이 될 것이라 생각한다.

그래도 되도록이면 우리는 앞으로 참조형 변수를 선언할 때

new 생성자를 사용해서 변수 선언을 하도록 하자.

Comments