본문 바로가기

JAVA

[Snack Java] 1. 자바의 타입(Type of JAVA)

우리가 프로그래밍 언어를 이용해 다루고자 하는 것은 결국 '데이터'이다.

 

우리가 코딩을 하며 데이터를 다룰 때 컴퓨터는 데이터를 메모리에 임시로 기억해둔다. 따라서 컴퓨터는 데이터가 어떤 종류이고 얼만큼의 크기를 가지는지 알아야한다. 프로그래머는 데이터가 보관될 수 있도록 메모리 공간을 확보해야 메모리에 데이터를 집어 넣을 수 있다. 

 

문제는 데이터의 종류마다 필요한 크기가 다르다는 것이다. 이로 인해 데이터의 종류를 구분해야하는 필요성이 생겼는데, 자바 언어 개발자는 종류와 크기에 따라 데이터의 타입을 미리 나누어놨다. 

 

일단 자바의 타입은 크게 두가지로 나뉜다. 

 

ㅋㅋㅋㅋ

1. 기본 타입 또는 원시 타입(Primitive type)

- 변수에 데이터의 실제 값 저장

- 정수타입(byte, short, long, int), 실수타입(float, double), 문자타입(char), 논리타입(boolean)

 

2. 참조타입(reference type)

- 변수에 데이터가 저장된 주솟값 저장

- 함수(function), 배열(array), 객체(object), 클래스(class), 메소드(method) 등 나머지 타입

 

이렇게 두가지로 나뉘는 이유는 시스템에서 정의를 내린 최초의 타입인 원시 타입이 따로 존재하기 때문이다. 자바의 개발자들은 자바 시스템에 필요한 아주 기본적인 타입을 원시타입이라는 이름을 붙여 미리 정의를 해놓았다.

 

이전 객체지향 관련 글에서 말했듯, 이 원시 타입의 존재 때문에 자바는 순수 객체지향언어로 정의되지 않는다. 원시타입은 객체로 정의 되지 않기 때문이다. 오히려 루비나 파이썬과 같은 언어들이 자바의 원시타입에 해당하는 타입도 모두 객체로 여기기 때문에 순수 객체지향언어로 불린다.

 

그럼 참조 타입은 무엇인가? 원시타입으로 지정되지 않은 모든 데이터의 타입을 참조 타입이라고 하는데, 이 타입에 속하는 데이터는 변수에 데이터를 저장할 때 데이터를 직접 저장하지 않고 주솟값만 불러와 변수에 저장시킨다. 즉, 변수에 데이터를 삽입하는 것이 아니라 메모리에 저장된 데이터의 위치를 가리키는 것이다. 

 

참조타입이 생긴 이유는 간단한데, 객체나 함수와 같이 여러 군데에서 쓰이는 데이터를 변수에 하나씩 따로 저장하는 것은 매우 비효율적이기 때문이다. 

 

다음은 원시타입의 정리표이다.

정수 타입
(Integer)
타입 메모리 범위 설명 예시
byte 1byte -2⁷ ~ 2 - 1 가장 작은 정수 범위를 지닌 타입 byte bnum = 23;
short 2byte -2¹⁵ ~ 2¹⁵ - 1 int보다 작은 정수 범위를 지닌 타입 short snum = 123;
int 4byte -2³¹ ~ 2³¹ - 1 정수타입의 기본형  -20억부터 20억까지의 수 int num = 18479;
long 8byte -2⁶³ ~ 2⁶³ - 1 -900경부터 900경 범위의 가장 큰 정수 타입. 이 정수 타입은 숫자 뒤에 L을 붙여준다. 소문자는 1과 헷갈려서 안쓴다. long lnum =
1723414159224L;
실수타입
(real number)
float 4Byte -3.4*10³⁸ ~ 3.4*10³⁸ 이 실 수 타입은 뒤에 f나 F를 붙여준다. float real1 = 1.4f;
double 8byte -1.7*10³⁰⁸ ~ 1.7*10³⁰⁸ 자바의 실수 기본 타입 double real2 = 9.432;
문자 타입
(character)
char 2byte 0 ~ 2¹⁶ - 1 문자를 표현. 유니코드의 문자표의 문자가 지닌 숫자 값에 대응한다. 문자가 모인 문자열은 참조타입으로 따로 존재한다. 문자는 작은 따옴표인 ' '으로 감싸서 표현한다. char letter = 'Z';
논리 타입
(logic)
boolean 1byte true, false 참/거짓을 판별할 때 쓰인다. 1bit면 충분한 타입이지만 자바의 최소 데이터 값이 1byte이기 때문에 1byte를 차지하게 된다. boolean isGood =
false;

 

모든 타입이 해당 범위를 벗어나면 오버플로우(overflow), 언더플로우(underflow) 오류를 발생시킨다. 만약 byte 형의 최대 값인 127을 넘는 128을 값으로 가진 경우 -128로 순환해버린다! 즉, 순환오류가 발생하게 된다. 

 

참고로 1byte는 8bit를 표현할 수 있는데 1bit마다 0과 1를 표기 가능하다. 따라서 범위는 1과 0인 두 가지 상태를 나타내는 2의 n승으로 결정이되는데 1byte는 2⁸, 256개의 표현이 가능하다. 그런데 byte는 -2⁷부터 2⁷-1의 범위까지 표현한다. 

 

이유는 음수를 표현하기 위해서이다. 8bit 중 맨 앞의 1bit는 0일 때 음수, 1일때 양수를 표현하는 표현식으로 사용해, 남은 7bit만 사용하는 것이다.

 

그러면 양수에서 -1로 수가 하나 빠지는 이유는? 컴퓨터 세계에서 숫자는 0으로 시작한다는 것을 잊지말자. 0을 표현하기 위한 수가 하나 빠지는 것이다.

 

여담으로 실수타입의 차이는 부동 소수점의 방식 차이다. 부동 소수점은 또 할 얘기가 많고 길어지니 다음기회에... 

 

이 타입의 메모리가 굉장히 중요한데, 코딩을 하다보면 문자열로 입력된 값을 정수로 받거나 정수로 받은 데이터를 문자로 변환해야하는 등의 일이 엄~~~청나게 많다.

 

이를 형 변환(type casting)이라 한다. 다행히 메모리가 큰 타입에서 작은 타입으로는 자동 형 변환이 된다. 다만, long 타입을 int 타입으로 변환한다던지 double 타입을 byte로 변환하는 경우는 수동으로 형 변환을 선언해주어야 한다. 이 때 캐스팅 연산자인 ( )를 사용한다. 예를 들면

 

int a = 128; 으로 선언된 변수를 더 작은 데이터 타입으로 변환하려면

 

byte byteA = (byte) a 처럼 byte를 캐스팅 연산자에 담아 선언해주어야 한다. 여기서 반환하는 값은 -128이 나오는데 더 작은 데이터 타입으로 변환하면서 순환 오류가 발생하는 것이다. (byte의 최대 값은 127이다.)

 

사실 원시타입 간 변환은 큰 어려움이 있는 작업은 아니다. 나중에 참조형의 형변환에 대해 다룰 때 진짜 지옥을 보자.