문자형 데이터 타입 역시 char 한 가지밖에 없다.

문자를 저장하기 위한 변수를 선언할 때 사용되며,

char 타입의 변수는 단 하나의 문자만을 저장할 수 있다. 

 

 

 

<Char 타입의 저장 방식>

char ch1 = 'A';
char ch2 = 'a';
char ch3 = "B";		// 에러 : Type mismatch: cannot convert from String to char
char ch4 = 'CD';	// 에러 : Invalid character constant
char ch5 = '가';
char ch6 = '0';
char ch7 = 1;
char ch8 = 100000;	// 에러 : Type mismatch: cannot convert from int to char
char ch9 = 1.1;		// 에러 : Type mismatch: cannot convert from double to char

위 예제에서 ch3에 저장하려고 한 리터럴 "B"는

작은따옴표가 아닌 큰따옴표를 사용했기 때문에,

ch4에 저장하려고 한 리터럴 'CD'는

문자가 하나가 아니라 둘이기 때문에, 

ch9에 저장하려고 한 리터럴 1.1은

문자가 아닌 double 타입 실수이기 때문에 에러가 났다.

 

ch1에 저장한 리터럴 'A'와

ch2에 저장한 리터럴 'a',

ch5에 저장한 리터럴 '가'.

ch6에 저장한 리터럴 '0'은

char 타입에 맞는 문자형 리터럴이라 에러 없이 잘 저장된다.

 

그런데 왜 ch7에 int 타입 1은 에러 없이 저장되고,

왜 ch8에는 int 타입 100000은 저장되지 않고 에러가 발생되는 걸까.

 

 

 

문자형 데이터 타입 char에

문자가 그대로 저장되는 것이 아니라

'문자의 유니코드(정수)'가 저장되기 때문이다.

 

문자 'A'의 유니코드는 65이며,

변수 ch1에는 65가 저장된다.

 

이처럼 문자를 코드로 변환하는 것을 '문자 인코딩(encoding)',

반대로 코드를 문자로 변환하는 것을 '문자 디코딩(decoding)이라고 한다.

 

문자를 저장할 때는 인코딩해서 숫자로 변환하여 저장하고,

저장된 문자를 읽어올 때는 디코딩해서

숫자를 원래의 문자로 되돌려야 한다.

 

게다가 컴퓨터는 1과 0, 이 두 숫자밖에 모르기 때문에

'A'의 유니코드 65는 16bit 2진법으로 인코딩되어

0000_0000_0100_0001으로 저장된다.

 

참고로 'a'의 유니코드는 97이며,

'가'의 유니코드는 44032,

'0'의 유니코드는 48이다.

A가 65면 B는 66, C는 67인 것과 같이

관련된 문자들이 연결되어 있기 때문에

A를 포함한 이 네 개의 문자들의 유니코드 값은 외워두면

특정 문자들의 시작점이기 때문에

연결된 문자들의 유니코드는 쉽게 구할 수 있다.

 

 

 

결과적으로 char 타입 변수에는

문자 리터럴 대신 문자의 유니코드를 입력해도 저장이 가능하다.

그래서 상단의 예제에서

변수 ch6에 int 타입 1이 저장될 수 있었던 것이다.

char chNum1 = 65;
char chNum2 = 97;
char chNum3 = 48;
char chNum4 = 1;

System.out.println(chNum1);
System.out.println(chNum2);
System.out.println(chNum3);
System.out.println(chNum4);

[실행결과]
A
a
0


(이라는 특수기호의 유니코드가 1이었다.)

 

 

 

그럼 같은 int 리터럴인 100000은 저장되지 않는 걸까.

그것은 char타입의 값의 범위 때문이다.

 

char 타입의 크기는 2byte로 16bit이며,

16자리의 2진수로 2¹⁶개(65536개)의 값들을 표현할 수 있다.

(저장 가능한 값의 범위 : 0~2¹⁶-1 또는 0~65535)

100000은 char 타입 값의 범위를 초과했기 때문에

저장되지 않는다.

 

문자는 정수형과 달리 음수개념이 없으므로

char 타입 변수에 저장할 수 있는 가장 작은 유니코드는 0이며,

char 타입 변수에 저장할 수 있는 가장 큰 유니코드는 65535이다.

char chNum5 = 0;
char chNum6 = 65535;

System.out.println("<" + chNum5 + ">");
System.out.println("<" + chNum6 + ">");

[실행결과]
< >
<>

char 타입 변수에 잘 저장되지만

0과 65535 둘다 출력되는 문자는 없다.

 

 

 

<char 타입의 형변환>

그렇다면 각각 문자의 유니코드는 어떻게 알 수 있을까?

char 타입의 문자를 int 타입의 정수로 형변환(캐스팅, casting)을 해야 한다.

형변환에 대해서는 추후에 자세히 학습하고

지금은 유니코드를 알아내기위한 방법으로만 이해하면 된다.

방법은 아래와 같이 문자 앞에 int 타입 형변환 연산자 (int)를 붙여주면 된다.

int code = (int)'A';
System.out.println(code);
System.out.println((int)'a');
System.out.println((int)'0');

[실행결과]
65
97
48

실행결과로 알아낸 문자 앞에 char 타입 형변환 연산자 (char)를 붙이면

char 타입으로 형변환 되어 다시 문자를 출력할 수도 있다.

System.out.println((char)65);
System.out.println((char)97);
System.out.println((char)48);

[실행결과]
A
a
0

 

나중에 형변환에서 배우겠지만

사실 아래 예제의 세번째 문장과 같이 (int)를 적지 않아도 유니코드를 알 수 있다.

char ch = 'A';		// 2byte
int code1 = (int)ch;	// 4byte
int code2 = ch;		// int > char 이므로 (int) 생략가능
		
System.out.println(code1);
System.out.println(code2);

[실행결과]
65
65

char 타입은 크기가 2byte이고 int 타입은 크기가 4byte로

int 타입이 char 타입보다 크기 때문에

형변환 연산자를 쓰지 않아도

자동 형변환되어 에러없이 저장된다.

int 말고도 long, float, double에도 저장이 가능하다.

 

같은 크기인 short 타입에도 char 타입을 저장할 수는 있지만

short 타입은 음수가 있기 때문에

char 타입을 전부 표현할 수 없어 부분 적으로만 가능하다.

 

char a = 'A';
short aa = a;				// 컴파일 에러 : Type mismatch: cannot convert from char to short
System.out.println((short)'a');
System.out.println((short)'가');	// 실행 에러 : Type mismatch: cannot convert from char to short

그래서 위 예제의 두번째 문장처럼

short 타입의 변수에 char 타입 변수의 값 저장은 아예 불가능하다.

세번째 문장처럼 prtinln()으로 화면 출력은 가능하나,

네번째 문장처럼 short 타입의 표현범위를 초과하면

실행시 에러가 발생된다.

('가'의 유니코드는 44032이며, short 타입의 최대값은 32767이다)

 

 

 

<char 타입의 연산>

문자는 유니코드로 저장되고

정수형으로 형변환이 가능하기 때문에

아래와 같은 연산도 가능하다.

 

<유니코드에 저장되어있는 자음과 모음 개수 확인>

System.out.println("자음은 " + ('ㅎ' - 'ㄱ' + 1) + "개");
System.out.println("모음은 " + ('ㅣ' - 'ㅏ' + 1) + "개");

[실행결과]
자음은 30개
모음은 21개

자음 : ㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ

모음 : ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ

 

<유니코드에 저장되어있는 한글 배치 확인>

System.out.println("가 다음에 저장된 글자는 " + (char)('가' + 1));
System.out.println((char)('가' + 1) + " 다음에 저장된 글자는 " + (char)('가' + 2));

[실행결과]
가 다음에 저장된 글자는 각
각 다음에 저장된 글자는 갂

유니코드 한글 저장 순서 : 가각갂갃간갅갆갇갈갉갊....

 

<유니코드에 저장되어있는 한글 개수 확인>

System.out.println("유니코드에 저장되어 있는 한글 개수는 " + ('힣' - '가' + 1) + "개");

[실행결과]
유니코드에 저장되어 있는 한글 개수는 11172개

유니코드 한글 : 가각갂 ... 힡힢힣 (자음, 모음 제외)