자바의 데이터 타입은 크게 원시 타입(Primitive Type)과 참조 타입(Reference Type)이 있다.
원시 타입은 쉽게 말해, 정수, 실수, 문자, 논리 리터럴등의 실제 데이터 값을 저장하는 타입이고,
참조 타입은 객체(Object)의 번지를 참조(주소를 저장)하는 타입으로 메모리 번지 값을 통해 객체를 참조하는 타입이다.
원시 타입
원시 타입의 종류는 byte, short, char, int, float, double, boolean이 있다.
int a = 10; 같이 코드를 작성했다면 정수 값이 할당될 수 있는 a라는 이름의 메모리 공간이 JVM 스택 영역에 생성되고, 10이라는 값이 들어간다. 즉, 원시 타입은 메모리 공간에 실제 데이터 값이 저장되어 있다.
[원시 타입에서의 주의사항]
JVM의 피연산자 스택이 피연산자를 4 Byte 단위로 저장 하기 때문에 int보다 작은 자료형의 값을 계산시 int 형으로 형변환 되서 연산이 수행된다.
정수형 데이터를 사용하게 되면 JVM에서 기본적으로 int형 데이터타입의 데이터로 인식을 해주게 된다.
int형 데이터 타입의 범위를 넘어서는 long 데이터 타입의 정수를 사용하고자 하는 경우에는 정수 데이터 맨 뒤 쪽에, 접미사 'l' 이나 'L'을 붙여줘야한다.
참조 타입
원시 타입을 제외한 타입들(문자열, 배열, 열거, 클래스, 인터페이스)을 말한다.
Java에서 실제 객체는 힙 영역에 저장되며 참조 타입 변수는 스택 영역에 실제 객체들의 주소를 저장하여, 객체를 사용할때 마다 참조 변수에 저장된 객체의 주소를 불러와 사용하는 방식이다.
new 키워드를 이용하여 객체를 생성하여 데이터가 생성된 주소를 참조한다.
Person p = new Person(); 이라는 코드를 작성했다면 p라는 이름의 메모리 공간이 스택 영역에 생성되고, 생성된 p의 인스턴스는 힙 영역에 생성된다, 즉, 스택 영역에 생성된 참조 변수 p는 힙 영역에 생성된 p의 인스턴스 주소 값을 가지게 된다.
- 정적 메모리 스택(Stack) 영역
스택 영역에는 기본타입 변수가 할당되고 변수의 실제 값들이 저장된다.
참조 타입의 변수들은 이 스택 영역에서 힙 영역에 생성된 객체들의 주소 값을 저장하고 있는다.
객체 안의 메소드의 작업이 종료되면 할당되었던 메모리 공간은 반환되어 비워진다. - 동적 메모리 힙(Heap) 영역
힙 영역에는 객체와 배열이 생성된다.
그리고 참조타입(배열, 클래스, 인터페이스 등)들이 이 객체들의 주소를 스택 영역에 저장한다.
기본타입 변수들과는 다르게 크기가 정해져 있지 않다.
프로그램 실행시 메모리에 동적으로 할당된다.
참조하는 변수가 없으면 자바의 가비지 컬렉터가 제거한다.
Wrapper class
프로그램에 따라 기본 타입의 데이터를 객체로 취급해야 하는 경우가 있다. 예를 들어, 메소드의 인수로 객체 타입만이 요구되면, 기본 타입의 데이터를 그대로 사용할 수는 없다. 이때 기본 타입의 데이터를 먼저 객체로 변환한 후 작업을 수행해야 한다.
이렇게 8개의 기본 타입에 해당하는 데이터를 객체로 포장해 주는 클래스를 래퍼 클래스(Wrapper class)라고 한다. 래퍼 클래스는 각각의 타입에 해당하는 데이터를 인수로 전달받아, 해당 값을 가지는 객체로 만들어 준다. 이러한 래퍼 클래스는 모두 java.lang 패키지에 포함되어 제공된다.
Boxing, Unboxing
Boxing(박싱)은 원시 타입을 참조 타입으로 변환 시키는 것을 말하고, Unboxing(언박싱)은 참조 타입을 원시 타입으로 변환 시키는 것을 말한다.
JDK 1.5부터는 박싱과 언박싱이 필요한 상황에서 자바 컴파일러가 이를 자동으로 처리해 준다. 이렇게 자동화된 박싱과 언박싱을 오토 박싱(AutoBoxing)과 오토 언박싱(AutoUnBoxing)이라고 부른다.
Integer num = new Integer(17); // 박싱
int n = num.intValue(); // 언박싱
System.out.println(n); // 출력 값: 17
Character ch = 'X'; // Character ch = new Character('X'); : 오토박싱
char c = ch; // char c = ch.charValue(); : 오토언박싱
System.out.println(c); // 출력 값: X
오토 박싱을 이용하면 new 키워드를 사용하지 않고도 자동으로 Character 인스턴스를 생성할 수 있다. 반대로 charValue() 메소드를 사용하지 않고도, 오토 언박싱을 이용하여 인스턴스에 저장된 값을 바로 참조할 수 있다.
원시타입 vs 참조 타입
1. 원시타입은 null을 담을 수 없지만, 참조 타입은 가능하다.
// 불가능
int i = null;
// 가능
Integer integer = null;
2. 원시타입은 제너릭 타입에서 사용할 수 없지만, 참조 타입은 가능하다.
// 불가능
List<i> list;
// 가능
List<Integer> list;
3. 원시타입 접근이 참조타입 접근보다 훨씬 빠르다.
원시타입은 '스택' 메모리에 값이 존재한다.
반면에 참조타입은 하나의 인스턴스이기 때문에 '스택' 메모리에는 참조값만 있고, 실제 값은 힙 메모리에 존재한다.
그리고 값을 필요로 할 때마다 언박싱 과정을 거쳐야 하니 원시타입과 비교해서 접근 속도가 느려지게 된다.
예외적으로 엄청 큰 숫자를 복사해야 한다면, 참조값만 넘길 수 있는 참조타입이 좋을 수 도 있다.
4. 원시 타입보다 참조 타입이 사용하는 메모리양이 압도적으로 높다.
출처
'Computer Science > Java' 카테고리의 다른 글
String, StringBuilder, StringBuffer의 차이 (0) | 2023.04.10 |
---|---|
동일성과 동등성 (0) | 2023.04.10 |
기타 제어자 - static, final, abstract (0) | 2023.04.10 |
접근 제어자 (1) | 2023.04.10 |
자바 컬렉션 프레임워크 - List, Set, Map (0) | 2023.03.30 |