들어가며
변수를 선언할 때는 반드시
'자료형'을 결정해 주어야 한다.
변수의 자료형을 결정한다는
것은 해당 변수에
값을 저장하고 참조하는 방식을
결정한다는 의미다.
즉, 변수의 자료형을 정수형으로
결정하면
앞서 설명한 정수의 표현 방식으로
값을 저장 및 참조하게 된다.
그리고 실수형으로 결정하면,
앞서 설명한 실수의 표현 방식으로
값을 저장 및 참조하게 된다.
정수 자료형
자바는 총 4개의 정수 자료형을
제공한다.
따라서 이들 자료형을 기반으로
변수를 선언하면,
이로 인해 할당된 메모리 공간에는
정수의 표현 방식을 기준으로
값을 저장 및 참조하게 된다.
따라서 정수 자료형으로 선언된
변수에는
소수점 이하의 값을 포함하는
실수를 저장할 수 없다.
그리고 자바에서 제공하는 4개의
정수 자료형이 갖는 차이점은
정수의 표현에 사용하는 메모리
공간의 크기에 있다.
short는 2바이트를 기준으로
정수를 표현하고
int는 4바이트를 기준으로 정수를
표현한다.
따라서 변수를 short로 선언하면
2바이트 크기의 변수가 만들어지고
int로 선언하면 4바이트 크기의
변수가 만들어진다.
자료형의 사용
이어서 2개의 코드 블록을
보여줄 테니,
어떤 코드가 더 합리적인지
판단해 보라.
첫 번째 코드 블록은 다음과 같다.
int main(String[] args){
short num1 = 11;
short num2 = 22;
short result;
result = num1 + num2;
......
}
두 번째 코드 블록은 다음과 같다.
int main(String[] args){
int num1 = 11;
int num2 = 22;
int result;
result = num1 + num2;
}
일단 다음과 같은 의견이
있을 수 있다.
등장한 숫자는 2바이트 정수로
표현할 수 있으므로,
short형 변수를 선언하는 것이 옳다.
그렇다면 다음 예제를 컴파일
및 실행해보자.
public class temp {
public static void main(String[] args){
short num1 = 11;
short num2 = 22;
short result = num1 + num2;
System.out.println(result);
}
}
/*
아무튼 컴파일 에러 발생
*/
안타깝게도 컴파일 오류가
발생한다.
논리적으로 보면 문제가 없지만,
자바의 관점에서 본다면
문제가 있기 때문이다.
그 이유는 다음과 같다.
자바는 정수형 연산을
int형으로 진행합니다 ㅎㅎ
자바 가상 머신은 정수형 연산을
4바이트 int형으로만 진행한다.
따라서 byte형 변수나 short형
변수에 저장된 값을 대상으로
덧셈과 같은 연산을 진행하면
이를 먼저 int형 값으로 변경해
버린다.
즉 위 예제에서는 덧셈 연산
이전에, 다음 과정을 거친다.
변수 num1과 변수 num2에 저장된 값을
int형으로 변환한다.
이렇듯 변환을 하고 이어서 덧셈을
진행하는 것까진 문제가 없다.
하지만 덧셈의 결과를 변수
result에 저장하는 과정에서
문제가 발생한다.
변수 result는 2바이트 short형이고,
연산 열과는 4바이트 int형이다.
변환된 2개의 int형 데이터를
대상으로 한 덧셈 연산의 결과도
4바이트 int형으로 만들어진다.
따라서 이 값을 2바이트 크기의
변수 result에 저장하는 것은 불가하다.
정리하면, 연산을 동반하는
상황에서
변수를 byte, short로 선언해도
생각보다
메모리가 절약되지 않고, 오히려
데이터 변환 과정만 추가된다.
그러니 그냥 int로 선언하는 것이
낫다.
long형에서의 int형으로의 변환
long형은 8바이트이고 int는
4바이트다.
따라서 long형 데이터를 int형으로
변환해버리면
데이터의 손실이 발생한다.
때문에, long형 데이터를 피연산자로
하는 연산 시에는
int형으로의 변환이 발생하지
않는다.
지금 설명한 내용만 보자면,
byte와 short형은
도대체 어디다가 써먹는 것일까
궁금해 진다.
우리가 프로그램상에서 표현하는
데이터 중에는
잦은 연산이 필요한 데이터도
있지만
그렇지 않은 데이터도 있기
때문이다.
예를 들어서 게임의 지형,
캐릭터 등을 그리기 위한
3D 그래픽 정보나 음원 정보는
매우 많은 수의 숫자 정보로
이루어져 있다.
때문에 이러한 경우에는
int형보다 작은
byte형 또는 short형으로
데이터를 저장하는 것이
의미가 있다.
설령, 그 데이터들을 대상으로
약간의 연산을 해야 해도 말이다.
실수 자료형
소수점 이하의 값을 지니는
실수의 저장 및 표현을 위한
자료형은 그 크기에 따라서
float와 double로 나뉜다.
이들은 모두 정밀도를 포기하고
표현의 범위를 넓힌 자료형으로,
float과 double의 선택 기준은
값의 표현 범위에 있지 않다.
물론 8바이트로 표현되는
double이
4바이트로 표현되는 float보다
더 넓은 표현 범위를 갖는다.
그러나 float도 충분한 값의
표현 범위를 갖는다.
위의 표에서 볼 수 있듯이,
아무튼 double형과 float형은
대충 엄청 넓은 범위를 표현할
수 있다.
그렇다면 둘 중에서 선택하는
기준은 무엇인가.
이 기준은 정밀도에 있다.
실수의 표현에 사용되는 바이트
수가 크면 오차의 크기는 작아진다.
실제로 float형은 6자리의
정밀도를 갖고
double은 15자리의 정밀도를
갖는다.
다시 말해 float형은 소수점
이하 6자리까지는 오차를
발생시키지 않고,
double형은 소수점 이하
15자리까지는 오차를
발생시키지 않는다.
소수점 이하 15자리까지 오차가 발생하지 않는다고 해도
double형 데이터 하나만 놓고
보면
소수점 15자리까지는 오차가
발생하지 않는다.
하지만 그 이하부터 오차가
발생하기 때문에,
오차가 존재하는 double형
데이터 둘 이상을 더하다보면,
소수점 이하 셋째 자리에서 오차가
발견될 수도 있다.
따라서 실수의 계산은 기본적으로
오차가 존재한다고 가정해야 한다.
문자 자료형
컴퓨터 프로그램은 대부분,
인간과의 상호작용을 필요로
하기 때문에,
문자의 표현은 매우 중요하다.
그러나 하드웨어는 수를
인식하고 표현하는 장치다.
따라서 문자의 표현은,
하드웨어 위에서 동작하는
소프트웨어의 몫일 수 밖에 없다.
그렇다면 소프트웨어 상에서
어떻게 문자를 표현하는가?
하드웨어가 수밖에 인식을
못하기 때문에,
문자 하나하나에 숫자를 부여하는
수밖에 없다.
예를 들면, 다음과 같이 문자
표현에 대한 약속을 하고
이를 운영체제에 적용하는
것이다.
문자 'A'는 65로 표시하기로 약속한다.
이러한 '문자의 표현에 대한
약속'을 가리켜 '문자 셋(Character Set)'
이라고 하는데,
이러한 문자 셋의 설계는 지역 및
국가별로 각각 이루어져 그 수가
다양하다.
때문에 데이터를 주고 받거나
여러 국가의 언어를
동시에 표현하는 상황에서는
문제가 된다.
그래서 모든 나라의 문자를
수용하여,
전세계적으로 사용할 수 있는
문자 셋을 설계하게 되었는데,
이를 가리켜 '유니코드(Unicode)'
라고 한다.
유니코드는 문자 하나를
2바이트로 표현하는 문자체계다.
2바이트로 표현할 수 있는
데이터의 수는
2의 16승 개이므로,
총 6만 개 이상의 문자 표현이
가능하다.
즉 유니코드는 대다수 언어의
기본 문자를 표현할 수 있다.
자바의 char는 문자의 저장을
위한 자료형이다.
그리고 자바는 유니코드를
기반으로 문자를 처리한다.
따라서 다음과 같이 char형
변수 하나에
한글 문자 하나를 저장하는
것이 가능하다.
그리고 아래에서 보이듯이,
문자는 이렇듯 작은따옴표로
감싸서 표현해야 한다.
char ch1 = '헐';
char ch2 = '확';
그러면 char형 변수 ch1와
ch2에는
각 문자의 유니코드 값이
저장된다.
그럼 이와 관련하여 다음
예제를 보자.
public class temp {
public static void main(String[] args){
char ch1 = '헐';
char ch2 = '확';
char ch3 = 54736;
char ch4 = 54869;
char ch5 = 0xD5D0;
char ch6 = 0xD655;
System.out.println(ch1 + " " + ch2);
System.out.println(ch3 + " " + ch4);
System.out.println(ch5 + " " + ch6);
}
}
/*
실행 결과
헐 확
헐 확
헐 확
*/
위 예제의 다음 두 문장이
변수에 문자를 저장하는
기본 방식이다.
char ch1 = '헐'; // 문자 '헐'의 유니코드 값은 54736
char ch2 = '확'; // 문자 '확'의 유니코드 값은 54869
컴파일 과정에서 위의 문자들은
유니코드 값으로 치환된다.
즉 변수에 실제 저장되는 값은
유니코드 값이다.
때문에 다음과 같은 방식으로
문자를 저장할 수도 있다.
이는 결과적으로 컴파일러가
할 일을 대신한 것과 같다.
char ch3 = 54736;
char ch4 = 54869;
다음 문장은 유니코드 값을
16진수로 표현한 결과다.
자바에서는 16진수를 표현할 때
해당 16진수 앞에 '0x'를 붙인다.
char ch5 = 0xD5D0;
char ch6 = 0xD655;
그리고 위 예제를 통해
이해하고 알게 된 내용을
정리하면 다음과 같다.
- 자바 프로그램 내에서 문자는 작은따옴표로 묶어서 표현한다.
- 문자를 char형 변수에 저장할 때 실제 저장되는 것은 해당 문자의 유니코드 값이다.
유니코드를 지원하는 자바가,
다양한 언어를 표현할 수 있음을
보이기 위해 예제를 하나 더 제시하겠다.
public class temp {
public static void main(String[] args){
char ch1 = 0x3041;
char ch2 = 0x3051;
char ch3 = 0x3061;
char ch4 = 0x3071;
System.out.println(ch1 + " " + ch2 + " " + ch3 + " " + ch4);
ch1 = 0x3043;
ch2 = 0x3053;
ch3 = 0x3063;
ch4 = 0x3073;
System.out.println(ch1 + " " + ch2 + " " + ch3 + " " + ch4);
}
}
/*
실행 결과
ぁ け ち ぱ
ぃ こ っ び
*/
위 예제에서 보이듯이,
일본어를 직접 입력하지
않더라도
이렇듯 유니코드 값을 통해서
일본어를 표현할 수 있다.
그리고 아무리 자바가 유니코드를
지원하더라도
문자의 출력은 운영체제에
의존적이다.
따라서 자신이 출력하고자
하는 언어의 폰트가
운영체제에 설치되어 있어야
한다.
만약에 해당 국가의 폰트가
설치되어 있어야 한다.
만약에 해당 언어의 폰트가
설치되어 있지 않다면
정상적인 출력을 확인하지 못한다.
논리 자료형
앞서 설명한 정수, 실수, 문자
자료형은 익숙한 것들이다.
그러나 자바에는 이것 이외에
'참'과 '거짓'의 표현을 위한
'논리 자료형'이라는 것이
존재한다.
프로그램에서는 '참'과 '거짓'의
상황 또는 상태를
표현해야 할 일이 자주 발생한다.
그래서 자바는 이 두 상태의
표현을 위해
다음 2개의 키워드를 정의하고 있다.
true // '참'을 의미하는 값
false // '거짓'을 의미하는 값
그리고 이 두 상태의 표현을
위해
논리 자료형 'boolean'을
정의하였다.
따라서 int형 변수를 선언하고
그 변수에 값을 저장하듯이
boolean형 변수를 선언하고
그 변수에 true 혹은 false를
저장할 수 있다.
boolean isJump = false; // 변수 isJump 선언과 동시에 false로 초기화
그럼 다음 예제를 통해서 boolean형
변수의 선언을 보이겠다.
즉 이 예제를 통해서 논리 자료형의
존재를 확인하겠다.
public class temp {
public static void main(String[] args){
boolean b1 = true;
boolean b2 = false;
System.out.println(b1);
System.out.println(b2);
int num1 = 10;
int num2 = 20;
System.out.println(num1 < num2);
System.out.println(num1 > num2);
}
}
/*
실행 결과
true
false
true
false
*/
다음과 같이 문장을 구성하면
그 결과로 12가 출력된다.
System.out.println(7 + 5);
출력의 과정은 이렇다.
먼저 7과 5의 덧셈이
진행되고,
그 결과로 얻어진 12가
덧셈 연산을 대신하게 된다.
즉 연산 이후의 문장 구성은
다음과 같다.
System.out.println(7 + 5);
↓
System.out.println(12);
마찬가지로 위 예제의 다음
두 문장 역시
부등호 연산이 먼저 진행된다.
이때 부등호는 수학에서의
부등호 의미를 갖는다.
System.out.println(num1 < num2); // num2이 num1보다 더 큰가?
System.out.println(num1 > num2); // num1이 num2보다 더 큰가?
그래서 그 결과인 true 또는
false가 다음과 같이 부등호
연산을 대신하게 된다.
System.out.println(true);
System.out.println(false);
그렇게 true와 false가 출력된다.
참고 및 출처
|