1. 논리형 (boolean)
논리형 타입에는 boolean 타입 한가지 밖에 없다. boolean 타입은 true와 false 중 하나를 저장할 수 있으며 디폴트 값은 false이다.
true와 false 만 표현하면 되기 때문에 1bit만으로 구현 가능하지만 자바에서 데이터를 다루는 최소단위가 byte기 때문에 boolean의 크기가 1byte이다.
2. 문자형 (char)
문자형 역시 char 하나밖에 없다. 문자를 저장하기 위한 자료형이고 단 하나의 문자를 저장할 수 있다.
char 타입의 변수에 문자를 저장하는데 실제로는 문자가 아닌 문자의 유니코드로 변환되어 정수값이 저장된다.그렇기 때문에 문자 리터럴이 아닌 정수값을 사용하여 유니코드를 직접 저장할 수도 있다.
만일 저장되어있는 문자의 유니코드가 궁금하다면 int 형으로 변환하여 정수값을 출력하면 된다.
- 특수 문자 다루기
영문자 이외에 tab이나 backspace 등의 특수문자를 저장하려면 특수한 문자 리터럴을 사용해야 한다.
tab | \t |
backspace | \b |
form feed | \f |
new line | \n |
carriage return | \r |
\ | \\ |
' | \' |
" | \" |
unicode char | \u{unicode characther} |
- char 타입의 표현형식
char 타입의 크기는 2byte (16bit) 이므로, 16자리의 2진수로 표현할 수 있는 정수의 개수인 2^16개의 코드를 사용할 수 있다.
char 타입은 앞서 말한 것과 같이 유니코드 형태로 문자를 저장하기 때문에 정수형과 동일한 형식으로 값이 저장된다. 다만 정수형과 달리 음수를 저장할 필요가 없기 때문에 2^16개의 값 모두를 표현할 수 있기 때문에 0~65535의 표현범위를 가진다.
- 인코딩과 디코딩 (encoding & decoding)
컴퓨터는 문자가 아닌 숫자만을 인식하기 때문에 문자형도 숫자로 변환하여 저장한다. 그렇다면 문자를 숫자로 변환하는 기준은 어떤 것일까? 이는 바로 유니코드를 기준으로 변환한다.
유니코드 표를 기준으로 문자와 숫자의 변환이 이루어진다. 이처럼 문자를 코드로 변환하는 것을 문자 인코딩, 반대로 코드를 다시 문자로 변환하는 것을 문자 디코딩이라고 한다.
- ASCII
american standard code for information interchange
정보교환을 위한 미국 표준코드로 128개의 문자 집합을 제공하는 7bit 부호이다.
숫자와 영문자들이 연속적으로 모여서 배치되어있기 때문에 프로그래밍에서 자주 사용한다.
- 확장 아스키와 한글
자바에서 데이터는 byte 단위로 다뤄지는데 아스키코드의 경우 7bit만 사용하기 때문에 한 bit가 남는다. 이 공간을 활용하여 문자를 추가로 정의한 것이 확장 아스키이다.
확장 아스키에 추가되는 문자는 국가와 기업에 서로의 필요에 따라 다르게 되는데 그 중에서 대표적인 것이 ISO (국제표준화기구)에서 발표한 것들이 있다.
한굴의 경우 cp949, 확장 완성형을 사용하여 인코딩을 진행한다.
- 코드 페이지 (code page, cp)
여러 국가나 조직에 따라 다르게 적용하는 확장 아스키를 IBM에서 코드 페이지라 이름을 붙이고 CP xxx 와 같은 형식으로 이름을 붙여 사용하고 공유했다.
- 유니코드 (Unicode)
전 세계의 모든 문자를 하나의 통일된 문자집합으로 표현하고자 만들어낸 것이 유니코드이다.
유니코드 문자 셋에 번호를 붙인 것을 유니코드 인코딩이라고 하는데, 인코딩은 UTF-8, UTF-16, UTF-32 등이 있다. 자바에서는 UTF-16을 사용한다. UTF-16은 모든 문자를 2byte의 고정크기로 표현하고 UTF-8은 하나의 문자를 1~4byte의 가변크기로 표현한다.
3. 정수형 - byte, short, int, long
정수형에는 4개의 자료형이 있으며 각 자료형별로 저장할 수 있는 값의 범위가 다르다. 각 자료형의 값의 범위는 다음과 같다.
byte (1) < short (2) < int (4) < long (8)
정수형의 기본 자료형은 int 타입이다.
- 정수형의 표현형식과 범위
어떤 진법의 리터럴을 변수에 저장해도 실제로는 2진수 형식으로 바뀌어 저장된다. 2진수가 저장되는 형식은 정수형과 실수형이 있는데, 정수형은 다음과 같은 형식으로 저장된다.
S + (n-1) 비트
-> S: 부호비트 (양수는 0, 음수는 1), n: 타입의 크기 (단위: bit)
모든 정수형은 부호가 존재하기 때문에 가장 왼쪽에 있는 bit를 부호 비트 (sign bit)로 사용하고 나머지 비트로 값을 표현한다. 그렇기 때문에 N비트로 표현할 수 있는 값의 개수는 부호비트를 제외하고 2^(N-1) 개이다.
정수형의 표현 가능한 값의 범위는 -2^(n-1) ~ 2^(n-1) - 1 까지의 범위이다. 양수의 경우 0을 표현해야하기 때문에 범위에서 1을 뺀다.
- 정수형의 선택기준
저장하려는 값의 범위에 따라 타입을 정할 수 있지만 왠만하면 int 형을 사용하는 것을 추천한다. byte나 short 형을 사용하면 메모리를 절약할 수는 있지만 값은 표현하는 범위가 작기 때문에 잘못된 결과를 얻을 수 있는 확률이 크다.
그리고 JVM의 피연산자 스택이 피연산자를 4byte 단위로 저장하기 때문에 4byte 보다 작은 자료형의 값을 계산할 때는 4byte로 변환하여 연산이 수행된다. 그렇기때문에 오히려 4byte를 사용하는 것이 효율이 좋다.
정수형 변수를 다룰 때는 int 타입으로 선언을 하고, 만약 int의 범위를 넘어가는 수에 대해서는 long 타입을 사용하면 된다.
- 정수형의 오버플로우
4bit의 이진수 1111에 1을 더하게 되면 어떻게 될까? 1111에 1을 더하게 되면 10000이 되지만 4bit로는 10000을 표현할 수 없기 때문에 0000으로 표현이 된다.
이와같이 해당 타입의 값 범위를 넘어서는 경우를 오버플로우라고 한다. 오버플로우가 발생한다고 하여 에러가 발생하는 것은 아니지만 우리가 원하는 기대했던 결과가 아닌 잘못된 결과를 얻을 수 있다는 문제가 발생한다. 그렇기 때문에 이러한 문제가 발생하지 않도록 알맞은 범위의 타입을 사용하여야 한다.
- 부호있는 정수의 오버플로우
부호없는 정수와 부호있는 정수는 값의 범위가 다르기 때문에 오버플로우가 발생하는 시점이 다르다. 부호있는 정수는 부호비트가 0에서 1이 될 때 오버플로우가 발생한다.
4. 실수형 - float, double
- 실수형의 범위와 정밀도
실수형은 실수를 저장하기 위한 타입으로 float, double 두가지 타입이 있다. float읜 4byte, double은 8byte의 크기를 가지고 있다.
실수형도 정수형과 같이 부호 비트를 사용하여 양과 음을 구분한다. 다른점으로는 실수로 소수점 아래의 수를 표현해야하기 때문에 얼마나 0에 가깝게 표현할 수 있는지도 중요한 부분이다.
실수형은 정수형과 다른 방식으로 표현되는데, 정수형이 부호 비트와 값을 표현하는 부분으로 표현하는 반면 실수형은 부호, 지수, 가수 세 부분으로 나누어져있다.
S (1) + E (8) + M (23)
-> E (지수), M (가수)
-> S + M * 10^E 의 값을 표현한다.
또한 실수형은 소수점 아래까지의 숫자를 표현하기 때문에 정밀도도 중요한 요소로 가지게 된다. float의 정밀도는 7자리인데, 이는 7자리의 10진수를 오차없이 저장할 수 있다는 뜻이다. 만약 이보다 큰 수를 저장하기 위해서는 double 타입을 사용해야한다.
- 실수형의 오버플로우와 언더플로우
실수형은 정수형과 달리 오버플로우 시에 무한대의 값을 반환한다. 그리고 정수형과 달리 숫자가 작아지면 언더플로우가 발생한다. 이때 변수의 값은 0이 된다.
- 실수형의 저장형식
±M * 10^E
-> S (sign bit), E (exponent), M (Mantissa)
- 부동소수점의 오차
정수와 달리 실수는 무한 소수와 같은 값들이 발생할 수 있기떄문에 오차가 발생할 수 밖에 없다. 특히나 10진수에서는 유한소수인 수들을 2진수로 표현하면서 무한소수가 되기도 하기 때문에 실수형의 정밀도를 넘어가서 오차가 발생하게 된다.
2진수로 변환된 실수를 저장할 때는 먼저 '1.xxx * 2^n' 의 형태로 변환하는데, 이 과정을 정규화라고 한다.
이때 1.을 제외한 나머지 소수 부분을 가수로 저장한다. 그리고 n을 지수로 저장하는데, 이때 지수는 기저법을 사용하기 때문에 기저인 127을 더하여 127 + n을 이진수로 변환하여 지수로 저장한다.
'프로그래밍언어 > JAVA' 카테고리의 다른 글
[JAVA] 연산자 (Operator) (0) | 2021.08.10 |
---|---|
[JAVA] 형변환 (casting) (0) | 2021.08.03 |
[JAVA] 진법 및 진법변환 (0) | 2021.08.01 |
[JAVA] 변수의 타입 (0) | 2021.07.29 |
[JAVA] 변수와 상수 (0) | 2021.07.28 |