본문 바로가기
Java/Java Basic

[Java Basic] 2. 변수 선언

by Rosmary 2022. 6. 21.
728x90
반응형

 

 

 

 

프로그래밍에서의 변수는, 어떠한 값을 저장하는 메모리 공간을 의미한다. 필자가 Python을 많아 사용하기도 했고, Python 관련 포스팅이 많아 Python을 예로 들어보자면, Python에서 a = 1 이라는 변수를 선언하면, 메모리에는 1이라는 정수값을 저장하기 위한 4 Byte 메모리 공간의 이름이 a로 할당되고, 여기에 1을 의미하는 00000000 00000000 00000000 00000001 이라는 4 Byte, 32 bit 값이 저장되는 것이다.

 

Java에서 사용하는 변수 역시, Python의 변수 저장법과 크게 다르지는 않다. 하지만 선언 부분에서 Python과 큰 차이가 하나 존재하는데, 변수에 저장되는 값의 Type 형을 변수 선언 시 명시해주어야 한다. 그리고 변수의 Type 명시를 위해서 먼저 이론적으로 알아야 할 것이 있다. 

 

이번 포스팅에서는 Java에서의 변수 선언과 관련된 내용 및 실제 선언 방법에 대해 포스팅해보려 한다.

 

 

1. Java의 변수 종류

 

Java의 변수는 크게 두 가지 타입으로 나뉜다. 하나는 기본형(Primitive Type), 또 다른 하나는 참조형(Refereced Type)이라고 한다. 프로그래머들이 코딩을 위해 변수 값을 저장하기 위해 선언하는 변수를 기본형이라고 보면 된다. 참조형은 다른 메모리 공간에 저장된 값을 사용해야 할 때, 이 값을 중복으로 변수 선언하기에는 메모리 낭비가 있으니, 중복값이 저장된 메모리 공간의 주소를 "참조"하는 변수라고 보면 된다.

 

이번 포스팅에서는 기본형 변수에 대해서만 집중하려하는데, 참조형 변수는 나중에 객체 지향과 Class와 관련된 내용에 도달해서야 꺼낼 수 있는 이야기이기 때문이다.

 

 

2. Java 기본형 변수의 타입과 메모리 할당 공간

 

Java의 기본형 변수는 큰 범주로 아래와 같이 나눌 수 있다.

 

-  논리형         :  참(true, 1) 또는 거짓(false, 0). Python에서 boolean 타입이라고 불린 그것이 맞다.

-  정수형         :  정수형 숫자. 세부적으로 byte, short, int, long 타입으로 나뉜다.

-  실수형         :  실수형 숫자. 세부적으로 double과 float 타입으로 나뉜다.

-  문자형         :  문자 한 글자. char 타입이라고도 한다.

 

필자가 서두에서 변수 선언 시 Type을 명시하면 해당 Type에 맞는 메모리 공간이 미리 변수에 할당된다고 언급했다. 각각의 Type은 변수 선언 시, 메모리 공간이 아래와 같이 할당된다.

 

-  논리형               :  8 bit (1 Byte)

-  정수형, byte      :  8 bit (1 Byte)

-  정수형, short     :  16 bit (2 Byte)

-   정수형, int         :  32 bit (4 Byte)

-   정수형, long      :  64 bit (8 Byte)

-   실수형, float      :  32 bit (4 Byte)

-   실수형, double  :  64 bit (8 Byte)

-   문자형, char      :  16 bit (2 Byte)

 

 

3. 각 변수 타입이 표현할 수 있는 범위

 

숫자와 관련된 변수 타입은 각각 자신이 표현할 수 있는 수의 범위가 지정되어 있다. 먼저, 정수형의 예시로 byte를 보자.

 

(1) 정수형 

 

byte는 1 Byte의 메모리 공간이 할당되기 때문에 8개의 0과 1로 숫자 표현이 가능하다. 따라서 가장 작은 수인 0(00000000)과 가장 큰 수인 255(11111111)까지 표시가 가능하다. 하지만 정수에 양수만 있지 않기 때문에 음수까지 고려한다면, Byte가 표현할 수 있는 수의 범위는 최소값 -128부터 최대 127까지가 된다.

 

**  참고

1) 정수형 Type의 경우, 가장 맨 앞자리 bit를 +, - 부호를 나타내는데 사용한다. 맨 앞자리 bit를 제외한 나머지 7자리 이진법으로 나타낼 수 있는 값의 범위는 양수 한정 0~127까지다. 따라서 -128부터 127까지 표시가 가능하다.

 

2) 음수의 표시는 마지막 bit 자리를 제외한 나머지 bit 값을 양수 bit의 반대로 표시하면 된다. 예를 들어, -1과 1을 합치면 0이 되는데, 1은 00000001이고, 0(00000000)에서 이 1을 뺀 값이 바로 -1(11111111)이 된다. 마지막 비트를 제외한 나머지 숫자가 양수와 음수에서 각기 다르게 지정된 것을 확인할 수 있다. 참고로 -127은 10000001이고, -128은 10000000이다(-0이라는 값은 존재할 수 없다는 것을 생각해보자)

 

3) 이진법으로 -1과 1을 더하면 2의 9승 값인 256이 나타나야하는데, 메모리 공간은 단 1 Byte만 정의되어 있기 때문에 0으로 표시된다. 메모리로 인해 특정 범위를 넘어서는 값이 나타날 때, 기존 범위의 값으로 돌아오는 이러한 현상을 Overflow라고 한다. 아래의 그림을 참조하자.

 

위의 이진법이 1, 아래의 이진법이 -1을 나타낸 것이며 Byte 타입일 경우 합은 0이 된다.

 

 

 

위와 같은 방식으로 short, int, long도 사용 가능한 정수의 범위가 정해진다.

 

-  정수형, byte 범위   :  -128 ~ 127

-  정수형, short 범위  :  -32768 ~ 32767

-  정수형, int 범위      :  -2^31 ~ 2^31 - 1 (약 +/-20억)

-  정수형, long 범위   : -2^63 ~ 2^63 - 1

 

 

(2) 실수형

 

정수형과 마찬가지로, 실수형 변수 역시 할당되는 메모리 용량에 따라 세부 타입이 float과 double로 구분되며 이들이 표시할 수 있는 실수의 범위가 각기 다르다. 앞서 언급한대로 float은 4 Byte의 메모리를, double은 명칭에서도 알 수 있듯이 float 메모리 할당량의 두 배인 8 Byte를 할당받는다. 따라서 float이 double에 비해 표시할 수 있는 실수의 범위가 더 작다. 

- 실수형, float 범위    :  1.4 x 10^(-45) ~ 3.4 x 10^(38)
- 실수형, double 범위 :  4.9 x 10^(-324) ~ 1.8 x 10^(308)

추가로, 저장하는 실수 값의 경우 정수와 달리 오차가 발생할 수 있는데 이로 인해 사용가능한 값의 범위 뿐만 아니라 값의 정밀도도 고려해야 한다. 정밀도도 실수형 Type 마다 조금씩 다르다. float의 경우 최대 7자리의 10진수 를 오차없이 저장가능하며, double은 그 두배인 15자리의 10진수를 오차없이 저장 가능하다.

- 실수형, float 정밀도    :  7 자리
- 실수형, double 정밀도 : 15 자리

** 참고
1) 실수 값의 메모리 저장 방법은 정수형과 다르다. 실수 값이 메모리에 할당되는 경우, 메모리의 구조는 아래와 같다.

부호(s) - 1 bit
지수(E) - 8 bit / 11 bit
가수(M) - 23 bit / 52 bit

 

출처: hackr.io



2) 부호, 지수, 가수는 실수 표현 시 아래와 같이 나타낼 수 있다.

    부호(S) (가수(M)) x  2^(지수(E))  

3) 따라서 float의 지수부분은 -128부터 127까지의 값을 지닐 수 있게 되는데, 2^(-128) ~ 2^(127) 값을 십진수로 변환하면 10^(-45) ~ 10(38)로 환산된다. 반면 double은 지수부분이 -512 ~ 511까지 범위의 값을 가질 수 있으므로 십진수 변환 시 10^(-324) ~ 10^(308)로 환산된다.

4) 이 때문에 int와 float은 동일한 크기의 메모리 용량을 할당받음에도 불구하고, float이 int에 비해 표시할 수 있는 수의 범위가 더 넓다.

5) float과 double을 구분하여 사용하는 이유는 값을 표현할 수 있는 범위 때문이 아니라, 값을 정확히 표현하는 정밀도로 인한 것이다. double의 경우 float에 비해 정밀도가 높기 때문에 훨씬 작은 오차로 값을 저장하는 것이 가능하기 때문이다. float은 2진수 23 bit로 10진수 7자리의 값을 저장할 수 있기 때문에 정밀도가 7자리인 것이며, double은 52 bit 2진수로 표시 가능한 10진수 자릿수가 15자리이기 때문에 정밀도가 15자리인 것이다. 조금 더 쉽게 이야기하자면, float은 소숫점 6자리까지, double은 소숫점 14자리까지는 오차없이 저장가능하다.

 

 

 

(3) 문자형

 

정수, 실수와 달리 문자형 타입은 char이라는 타입 하나만 존재하며, 이 타입은 2 Byte의 메모리 공간을 할당받아 문자를 표시한다. 숫자야 2진수 표시 시 10진수로 변환하면 된다고 하지만 문자로의 변환은 어떻게 진행되는 것일까?

사실, 우리가 사용하는 각각의 문자도 숫자로 표현이 되도록 미리 세팅이 되어 있다. 가장 처음 나온 것이 아스키 코드(ASCII)라는 것인데, 알파벳 대/소문자, 숫자, 특수기호 - 옛 PC의 조상격 되는 컴퓨터에서 인쇄와 전송 제어용으로 사용된 문자라고 한다 - 및 공백 등 128 글자를 7 bit 로 표시한 것이 그 시초다. 이 아스키코드에 의하면, 대문자 A는 10진수 65와 매칭되며, 2진법으로 표현 시, 00100001로 나타낼 수 있다. 대문자 B는 그 다음값인 66이며 2진법으로 001000010이 된다. 



하지만 컴퓨터는 영문 뿐만 아니라 아랍어나 한글, 일어의 가타가나와 히라가나도 표현을 할 수 있어야 했기 때문에 7 bit로는 전 세계의 모든 문자를 표현하기가 어렵다. 따라서 전 세계 문자를 2 Byte로 표시할 수 있도록 변경한 것이 유니코드(Unicode)다. 이 유니코드에 따르면, 한글 '가'는 10진수로 44032 값을 가지게 된다. 

컴퓨터의 경우 문자를 코드(숫자)로, 혹은 코드를 숫자로 변환해야 할 필요성이 있는데, 이를 인코딩 / 디코딩이라고 한다. 만약 인코딩과 디코딩이 원할하게 이루어지지 않는다면 아래와 같이 글자의 깨짐 현상이 발생하게 된다.

 

 

 

(4) 논리형

논리형의 경우 true / false, 즉 0과 1로 표시되는 값이다. 단순히 생각했을 때 1 bit만 있어도 표현이 가능한 값인데 왜 1 Byte의 메모리가 할당되는지 의아하신 분들이 있을텐데, Java의 데이터는 Byte를 최소단위로 사용하기 때문이다. 따라서 true의 경우 00000001, false는 00000000으로 표시된다. 

 

 

 

4. 변수 선언 실습

 

(1) 변수 선언

 

변수의 선언 방법은 다음과 같다. 

 

     변수타입 변수명 = 변수값(리터럴 - Literal 이라고도 한다);

 

변수명은 아래의 방식으로 지정한다.

 

1) 변수명은 영문, 숫자 및 특수문자 _와 $로만 구성할 수 있다.

2) 변수명은 숫자로 시작할 수 없다.

3) 예약어는 사용할 수 없다.

4) 변수는 영문 소문자로 작성한다.

 

Eclipse에서 코드 화면 좌측 붉은 바탕의 X 표시는 에러가 있음을 나타낸다.

 

 

(2) 논리형 변수 선언

 

논리형 변수의 선언은 true와 false로만 값 지정이 가능하기 때문에, 위에서도 예시를 들었지만 크게 어려운 부분이 없다. 단, Python에 익숙한 분들은 true와 false 가 아닌 True, False로 잘못 기입하는 경우가 매우 많은데, 이 부분만 주의한다면 크게 문제가 될 만한 것은 없다.

 

 

 

(2) 문자형 변수 선언

 

문자형 변수 역시 변수 선언 방식은 동일하다. 단, 리터럴로 작성되는 값이 반드시 홑따옴표로 둘러싸야한다. 만약 문자형 변수를 선언했는데, 문자 주변을 쌍따옴표로 둘러싸거나, 홑따옴표가 생략된 경우 변수 선언 시 에러가 발생한다.

 

 

변칙적으로 문자형 변수를 선언하는 방법도 있다. 만약 문자 'A'에 해당하는 ASCII 또는 유니코드 값을 리터럴로 사용하더라도 변수 출력 시 문자가 표시된다.

 

출력과 관련된 내용은 다음 포스팅에서 살펴볼 예정이다.

 

문자형 변수는 값 저장 시 유니코드 16진법으로 리터럴을 지정하는 방법도 사용 가능하다. 한글 '가'의 경우 유니코드 값 44032에 해당하는데, 이 값을 16진법으로 바꾸면 AC00이 된다. 유니코드 16진법 사용 시, 홑따옴표 내에 \u를 접미사로 16진법을 입력하면 해당 유니코드 값이 문자형 변수에 저장된다.

 

 

 

(3) 정수형 변수 선언

 

정수형 변수도 크게 어렵지 않다. 하지만, 정수형의 경우 세부 타입이 많이 나뉘는 특성으로 인해, 각 타입이 표현할 수 있는 값의 범위를 초과하는 값이 저장되지 않게 주의해야한다. 또한 long 타입의 경우, 리터럴 값이 int 타입 범위를 벗어나는 경우, 반드시 리터럴 접미사로 대문자 L을 추가해 주어야 한다.

 

 

Java에서는 특이하게도, 큰 수 표시 시, 수의 구분점을 언더바로 지정할 수 있게 되어 있다. 세 자리마다 언더바가 들어가 있더라도 출력 시에는 정상적인 정수로 표시된다.

 

만약 short로 선언된 값을 강제로 byte로 변환(형 변환이라고 한다. 다음 포스팅에서 언급할 예정이다)하면, overflow로 인해 정상적인 값이 나타나지 않을 수 있다. 아래의 예시는 short 변수에 128을 저장하고, 이 변수 리터럴을 byte로 강제 변환한 뒤 byte 변수에 저장하여 출력한 결과를 나타낸 것이다. 당연히 byte의 범위인 127을 초과하므로, 128 값이 overflow로 인해 -128로 출력되는 것을 확인할 수 있다.

 

 

 

 

 

 

 

(4) 실수형 변수 선언

 

실수형은 float과 double 두 가지 형태의 타입이 존재한다. 따라서 리터럴 값으로 소숫점이 존재하는 실수를 작성할 경우, 해당 리터럴 값이 float인지 double인지 명시해주어야 한다. long과 마찬가지로 접미사를 추가함으로써 float과 double 변수를 선언할 수 있다. 참고로, 접미사를 추가하지 않고 소수 리터럴 값을 변수에 저장하면, 자동으로 double 값으로 인식된다.

 

 

float과 double은 저장할 수 있는 값의 범위는 매우 넓기 때문에 사실 범위를 초과하는 값이 입력되는 에러는 잘 발생하지 않는다. 대신 이 둘은 소숫점 아래의 오차, 즉 정밀도와 관련해서 차이를 보인다. 위의 예시를 보면, 실제 저장한 소수 값에 비해, float은 소숫점 6~7자리까지만 동일하게 표시되는 것을 볼 수 있는 반면 double은 소숫점 15자리까지 동일하게 표시되는 것을 볼 수 있다.

 

 


 

 

이번 포스팅에서 문자열과 관련된 내용은 없는데, 문자열을 저장하는 기본형 변수 타입이 별도로 지정되어 있지않기 때문이다. 사실 문자열은 Java에서 문자형 변수가 배열로 집합한 형태를 띄고 있으며, String이라는 타입을 통해 변수 선언을 할 수 있기는 하다. 하지만 변수 형태가 기본형에 속한 것이 아니라 참조형 변수 범주에 들어가기 때문에 이 부분은 추후 포스팅에서 다시 언급하려 한다.

 

 

 

다음 포스팅에서는 변수값의 화면 출력과 형 변환(Type Casting)에 대해 알아보려 한다.

 

 

Fin.

반응형

댓글