[JAVA] 변수란? 변수타입?

프로그램 언어를 배울때 항상 먼저 배우거나 집고 넘어가는 것이 있죠? 네 맞습니다. 

변수라는 것입니다. C언어나 Java에서는 int, char, float 등 자료형에 따라 다르고, Javascript에서는 모든 변수를 그냥 var로 사용하죠. 물론 또 개발 언어마다 조금씩 차이가 있습니다.

하지만, 기본적으로 "변수"라는 기본 개념은 모든 언어에서 모두 동일합니다. 이번 포스팅은 이 변수에 대하여 낱낱이 파헤쳐 봅시다. 


아! 참고로 변수에 대하여 정말로 낱낱이 땅끝까지 파헤치자면 이 한번의 포스팅으로는 부족합니다. 따라서 오늘은 일차적으로 가장 기본이 되는 변수의 정의와 원시타입에 대해서만 낱낱이 살펴보도록 하겠습니다.



변수란 무엇일까?

자! 일단 변수란 무엇일까요?

변수란? 물어보면 가장 먼저 사람들은 당당히 말을 하죠. 

"변하는 수"

물론 이 말도 틀린 말은 아닙니다. 우리 프로그래밍에서는 변수라는 공간에 값이 항상 변하는 그리고 그런 용도로 사용하려는 것이 변수니까요.

변수는 영어로 "Variable"라고 읽습니다. 이것을 사전에서 찾아보면 "변화하기 쉬운, 변덕스러운, 다양한"이라는 의미를 갖습니다. 뭐 이 말도 틀린 말은 아니네요.

하지만! 우리는 개발자로도 더 프로그래밍 적인 의미를 원합니다. 그래서 이렇게 정의를 했죠.

변수란? 데이터(값)을 저장할 수 있는 프로그램의 저장 공간!

서론이 길었네요. ^^. 항상 무언가 정의를 내리기란 쉽지 않습니다..ㅎㅎㅎ

변수를 좀 더 이해하기 위해 아래의 그림을 예를 들어 보겠습니다.


위와 같이 우리가 물을 마셔야 한다면, 물을 마시기 위해 당연히 물 컵이 있어야겠죠. 

아! 물통에 입을 대고 드시는 분들도 계시지만... 그러면 엄마한테 혼납니다. ㅎㅎ

아무튼 이렇게 물을 마시기 위해 물을 담을 컵을 준비하는 것을 프로그래밍에서는 "데이터를 사용하기 위해 변수를 선언한다"라고 이야기 할 수 있습니다. 
그럼 위 그림 내용을 글로 정리해보면...
  1. 물 컵을 준비 한다       -> 변수 선언
  2. 물 컵에 물을 따르고    -> 변수 초기화
  3. 물 컵의 물을 마신다    -> 변수 사용

이렇게 정리할 수 있습니다. 따라서 변수를 사용할 때는 항상 "선언 > 초기화 > 사용"의 3가지를 꼭 기억하시기 바랍니다. 그런데 간단히 말하면 결론은 아래와 같이 정리해도 될 거 같습니다.

또한, 물을 먹을 때는 물 컵을 이용하고, 밥을 먹을 때는 밥 그릇을 그리고 반찬을 먹을 때는 반찬 그릇을 이용하듯 변수도 자료형(Data Type)에 따라 사용하는 변수 타입이 다릅니다.

변수 타입에 대한 자세한 내용은 다음으로 미루고 먼저 변수는 그럼 왜 사용하는지 알아보고 갑시다. 변수를 사용하는 이유는 간단히 말하면, "변하는 데이터를 사용하기 위해 변수를 사용한다."라고 말할 수 있습니다.

먼저 왼쪽 그림에서 보는 것과 같이 먼저 각각의 타입에 맞는 값(Data)를 각각의 변수 타입에 저장을 합니다. 그리고 이대로 사용을 하면 그냥 처음 넣은 값(초기화)인 4, 7.5, "영희"라는 변수 값을 사용하겠죠.  하지만, 이렇게 사용하면 변수를 사용하는 의미가 별로 없겠죠. 값이 변해야 진정한 변수라 할 수 있겠죠?

그래서 우리는 오른쪽 그림과 같이 해가 바뀔수록 늘어가는 영희의 몸무게와 나이를 바꿔줘야 합니다. 그리고 2030년 나이를 먹은 영희는 이름이 마음에 들지 않았나 봅니다. 이름을 개명까지 했네요.^^

이와 같이 시간이 지남에 따라 혹은 사용자의 의지나 생각에 따라 변화하는 값을 컴퓨터에서 처리하기 위해 우리 개발자 들은 변수를 사용합니다.


자! 여기까지 주저리 주저리 길게 떠들었는데요 간단히 정리하겠습니다.

  • 변수란 변하는 데이터를 특정 타입에 따라 저장하기 위해 선언하는 데이터 저장 공간이다.
  • 변수에서 변수 선언 -> 변수 초기화 -> 변수 사용 3가지를 꼭 기억하자.
  • 변수 타입에는 기본적으로 논리형(boolean) 정수형(int), 실수형(double), 문자형(char), 문자열(String)이 있다.

변수 타입에 대해서는 아래에서 더 자세히 다뤄보겠습니다. 일단 여기까지만 아셔도 오늘 많은 것을 배운 것이니 너무 조급해 하지 마세요. ^^


변수 타입

이렇게 그림과 같이 구분할 수 있을 거 같네요. 이와 같이 크게 원시타입(Primitive Type)와 참조타입(Reference Type)로 구분되며, 원시타입에는 논리형, 정수형, 실수형, 문자형이 존재하고, 참조타입에는 객체(Object)를 상속받은 클래스(Class) 타입인 Array, String,. List, Map 등이 존재합니다.

눈치 빠르신 분들은 보자마자 눈치 채셨겠지만 원시타입은 소문자로 시작하고 참조타입은 대문자로 시작한다는 것을 알아 채셨을 것입니다. 이처럼 자바에서는 "클래스를 만들때 약속으로 첫글자는 무조건 대문자로 시작하자"라고 묵시적으로 정한 규칙이 있습니다.

개발은 대부분의 경우 독불장군처럼 혼자 할 수 없기 때문에 이렇게 규칙을 정하고 정해진 규칙을 지키는 것이 보다 효율적이로 소통하는 협업의 기술이라 말할 수 있겠죠.

가끔 이렇게 규칙을 잘 지키지 않는 개발자들이 있는데 이러면 회사에서 퇴장 당할 수 있습니다. 그러니 최대한 지키도록 노력합시다...^^


원시타입은 말그대로 원시적인 타입으로 개발에서 가장 기본적인 변수입니다.

  • 논리형 : boolean으로 true, false의 값을 가진다. true/false가 문자가 아님에 주의한다. 
  • 정수형 : integer의 약자로 int가 기본형이며 1, 2, 3, 10, 20과 같은 정수를 저장한다.
  • 실수형 : double이 기본형이며 1.1, 3.1, 10.0 과 같은 실수를 저장한다.
  • 문자형 : character의 약자로 char로 사용하며 문자 한 글자 'a', '한', '#' 등을 저장한다. 문자 한글자를 표현하는 방식으로 앞뒤 ' 를 사용하는 것에 주의하자.

참조타입에서 참조(Reference)라는 말은 원래 메모리 참조하여 실제 데이터가 들어 있는 메모리로 이동한다는 의미에서 생긴 말이지만 그냥 "원시타입을 참조하여 확장한 개념으로 만들어진 타입이다." 라고 생각하고 넘어가도 일단은 크게 무리는 없을 것 같습니다.

  • 문자열 : String으로 문장 "Hello World!", "안녕하세요", "방가! 방가! @,.@"와 같이 문장을 저장하기 위한 공간입니다. 원시타입과 달리 기본적으로 저장할 수 있는 길이에는 제한이 없습니다.
  • 이처럼 기본적으로 가장 많이 사용되는 각 타입의 대표적인 타입에 대하여 살펴보았습니다. 이제 좀 더 자세히 각 타입의 길이에 대하여 살펴 보겠습니다.
  • 논리형 : boolean[1byte(8bit)] 하나만 존재한다.
  • 정수형 : int[4byte(32bit)]를 기준으로 절반 작은 short[2byte(16bit)] 두배 큰 long[8byte(64bit), 그리고 가장 작은 byte[1byte(8bit)] 가 존재한다.
  • 실수형 : Java에서는 double를 대표로 사용하지만 floating-pint(부동 소수점)에서 기본 개념을 가져온 것으로 float[4byte(32bit)]의 작은 용량으로 두배 큰 double[8byte(64bit)]를 기본으로 사용한다.
  • 문자형 : char[2byte(16bit)]로 원래는 아스키 코드로 1byte 였으나 한글, 중국어 등 다양한 문자를 표현하기 위해 유니코드로 확장되며 2byte를 기본으로 사용한다.
  • 문자열 : 참조타입으로 객체의 메모리 주소(4byte 정수)를 가지지만 실제 길이는 데이터 영역에 저장되므로 길이는 제한이 없다.

위의 내용을 표로 보다 자세히 정리하면 아래와 같습니다.


Eclipse를 통해 범위를 확인하려면 아래와 같은 코드를 통해 확인 할 수 있습니다.

// 정수형 변수의 최소 최대값
System.out.printf("%d ~ %d\n", Byte.MIN_VALUE, Byte.MAX_VALUE);
System.out.printf("%d ~ %d\n", Short.MIN_VALUE, Short.MAX_VALUE);
System.out.printf("%d ~ %d\n", Integer.MIN_VALUE, Integer.MAX_VALUE);
System.out.printf("%d ~ %d\n", Long.MIN_VALUE, Long.MAX_VALUE);
// 실수형 변수의 최소 최대값
System.out.printf("%f ~ %f\n", Float.MIN_VALUE, Float.MAX_VALUE);
// 표현 값이 너무 크므로 지수형으로 표현
System.out.printf("%e ~ %e\n", Double.MIN_VALUE, Double.MAX_VALUE);
// 문자형 변수의 최소 최대값
// Character의 경우 반환 값이 char이므로 (int)로 강제 형변환하여 정수로 표시
System.out.printf("%d ~ %d\n", (int)Character.MIN_VALUE, (int)Character.MAX_VALUE);

위에서 보면 정수형과 실수형 처럼 숫자를 표현하는 것은 음수와 양수로 구분하여 각각 절반 정도의 값을 가지며 그 외 논리형은 true/false 단 두개의 키워드(문자가 아님에 주의하자)만 허용하고 문자형에서는 0 ~ 65,535 까지의 값을 가진다는 것에 주의하자.

이제 좀 준비 운동도 끝났겠다. 본격적으로 깊이 있게 개발자 관점에서 논리적으로 접근해 보도록 하겠습니다. 마음의 준비 단단히 하세요~~~~~!



위 그름에서 먼저 byte를 살펴보면 앞서 우리는 byte가 1byte = 8bit라는 것을 배웠습니다. 8bit는 2진수로 표현하면 00000000 ~ 11111111으로 10진수로는 0 ~ 255까지의 값, 즉 0을 포함하여 256개에 해당하는 숫자를 표현할 수 있습니다.

하지만 위에서 byte 자료형은 음수와 양수를 모두 표현하기 위해 -128 ~ 127 까지의 숫자를 표현합니다. 이것은 위 그림의 byte에서 보는 바와 같이 맨 앞자리(MBS)를 프로그래밍 언어에서 일반적으로 부호(Sign)이라고 규칙을 정했습니다. 개발 언어에 따라서는 특히 C 개발 언어 같은 경우는 부호가 없는 정수를 Unsigned int로 부호가 있는 정수를 Signed int라고 더 세분화 하여 사용하지만 우리는 Java를 배우는 중이므로 복잡한 이야기는 하지 않겠습니다.

즉, 부호 비트를 하나 빼야 하므로 00000000 ~ 01111111으로 값은 맨 앞자리 부호가 0일경우 0 ~ 127 까지의 숫자를 10000000 ~ 11111111으로 이경우 맨 앞자리가 1이므로 -(음수)로 표현하고 0000000을 7bit가 표현할 수 있는 최대 값인 128개를 최대값으로 정하고 여기에 -를 붙여 -128로 정합니다. 그리고 0000001 처럼 1씩 증가할 때마다 -128에서 1개씩 감소시켜 -127, -126, -125 .... -1(1111111)까지 표현을 하게 됩니다. 이것은 컴퓨터의 내부 로직이 음수를 표현하는 방식입니다.

이와 같이 부호없는 자료형에서 최대값에서 1을 더하기 할 경우 최대값을 넘어가서 0으로 표현되는 것을 오버플로우라고 하며, 반대로 0에서  1을 빼기 할 경우 최소값 밑으로 간다고 해서 언더플로우라고 표현합니다. 아래의 그림을 보면 더 자세히 이해 하 실 수 있을 겁니다.



이상으로 변수에 대하여 아주 심도 있게 오버플로우와 언더플로우까지 익히셨습니다. 아마도 초보 개발자든 중급 개발자든 여기까지 이해하셨다면 당신은 변수에 대하여는 상위 1%라고 생각하시고 자부심을 가지시 바랍니다.

아주 지루하고 어려운 글을 읽어주셔서 감사합니다.


(참고)원시 타입과 참조 타입의 데이터 사용 성능

기본적으로 원시타입(소문자로 사용하는 타입)과 참조타입(대문자로 사용하는 Wrapping 타입)은 사용시 성능과 메모리를 사용하는 크기에서 차이가 발생합니다. 일단 참조타입이 객체(Object)를 상속 받은 클래스(Class) 이므로 메모리를 더 사용한다는 것과 처리 속도가 더 많이 걸린다는 것은 당연한 것입니다. 일단은 Object니 Class에 대해서는 나중에 알아보기로 하고 그냥 원시타입인 기본 트럭을 구조 변경하여 렉카차나, 탑차와 같이 변형하여 사용한다 라고 보면 무난할 것 같습니다. 그래서 아래의 차트는 이 처리 속도 대한 비교를 보여주는 차트입니다.

물론 일반적으로 프로그래밍 할 경우에는 요즘 PC 성능이 워낙 좋아서 대부분의 경우 큰 문제는 없습니다. 하지만 일단 성능이 느리다는 것을 알아두시면 추후 성능을 고려한 개발을 할 경우 도움이 될 거라 생각합니다.


댓글

이 블로그의 인기 게시물

[JAVA] 문자셋(Charset)

[JAVA] 문자열 비교[== vs equals()]의 차이