| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 가비지컬렉션
- 백준
- 프로그래머스
- 프로그래밍기초
- HashMap
- 클린코드
- 자바기초
- 정렬
- 예외처리
- 개발자팁
- 알고리즘
- 객체지향
- 코딩테스트준비
- 코딩공부
- 코딩인터뷰
- 개발공부
- 멀티스레드
- 파이썬
- JVM
- 코딩테스트팁
- 자바
- 자료구조
- 개발자취업
- 자바프로그래밍
- 알고리즘공부
- 자바공부
- 자바개발
- Java
- 메모리관리
- 코딩테스트
- Today
- Total
코드 한 줄의 기록
Java 기본 자료형과 래퍼 타입: 박싱/언박싱으로 알아보는 핵심 개념과 실무 활용법 본문
안녕하세요! 오늘은 Java를 공부하면서 한번은 꼭 이해해야 하는 기본 자료형과 래퍼 클래스에 대해 함께 알아보겠습니다. 저도 처음엔 "그냥 int 쓰면 되는데 왜 Integer라는 게 따로 있지?"라고 생각했는데, 알고 보니 각각 고유한 역할과 용도가 있더라고요.
기본 자료형(Primitive Type)이란?
Java에서 가장 기본이 되는 데이터 타입들로, 메모리에 값 자체를 직접 저장하는 방식입니다. 우리가 흔히 사용하는 int, double, char, boolean 등이 여기에 해당하죠.
int age = 25; // 정수형
double price = 3.14; // 실수형
char grade = 'A'; // 문자형
boolean isValid = true; // 논리형
기본 자료형의 특징
- 스택 메모리에 값이 직접 저장됩니다
- 메모리 사용량이 적고 접근 속도가 빠릅니다
- null 값을 가질 수 없으며, 각 타입마다 기본값이 정해져 있습니다
- 객체가 아니므로 메서드를 가지지 않습니다
래퍼 클래스(Wrapper Class)란?
기본 자료형을 객체로 감싸서 사용할 수 있게 만든 클래스입니다. 쉽게 말해 기본 타입의 "포장지" 역할을 하는 거죠.
기본 자료형과 래퍼 클래스 대응표
| 기본 자료형 | 래퍼 클래스 |
| int | Integer |
| double | Double |
| char | Character |
| boolean | Boolean |
| byte | Byte |
| short | Short |
| long | Long |
| float | Float |
Integer num = new Integer(10); // 래퍼 클래스 생성
Double price = Double.valueOf(3.14); // valueOf 메서드 사용
Boolean flag = Boolean.TRUE; // 상수 사용
래퍼 클래스의 특징
- 힙 메모리에 객체로 저장됩니다
- null 값을 가질 수 있습니다
- 다양한 유용한 메서드들을 제공합니다
- 컬렉션(ArrayList, HashMap 등)과 제네릭에서 사용 가능합니다
- 불변 객체(immutable)입니다
언제 기본형을, 언제 래퍼 클래스를 사용해야 할까?
실무에서 이 부분이 가장 헷갈리더라고요. 각각의 적절한 사용 시기를 알아보겠습니다.
기본형을 사용해야 하는 경우
- 단순한 값 연산이 많을 때
- 성능이 중요한 상황에서
- null 값이 필요하지 않을 때
- 메서드의 매개변수나 지역변수로 사용할 때
래퍼 클래스를 사용해야 하는 경우
- 컬렉션(List, Set, Map 등)에 저장할 때
- 제네릭 타입으로 사용할 때
- null 값을 표현해야 할 때
- 문자열 변환이나 파싱 등의 유틸리티 메서드가 필요할 때
// 기본형 사용 예시
int sum = 0;
for (int i = 0; i < 1000000; i++) {
sum += i; // 빠른 연산
}
// 래퍼 클래스 사용 예시
List<Integer> numbers = new ArrayList<>(); // 컬렉션에서는 필수
numbers.add(100);
// null 처리가 필요한 경우
Integer userAge = getUserAge(); // null일 수 있음
if (userAge != null && userAge > 18) {
// 성인 처리 로직
}박싱(Boxing)과 언박싱(Unboxing) 이해하기
박싱(Boxing)이란?
기본 자료형을 래퍼 클래스로 변환하는 과정입니다.
// 수동 박싱 (Java 1.5 이전)
int primitiveNum = 10;
Integer wrapperNum = new Integer(primitiveNum);
// 또는 valueOf 메서드 사용
Integer wrapperNum2 = Integer.valueOf(primitiveNum);
언박싱(Unboxing)이란?
래퍼 클래스를 기본 자료형으로 변환하는 과정입니다.
// 수동 언박싱
Integer wrapperNum = new Integer(20);
int primitiveNum = wrapperNum.intValue();
오토박싱과 오토언박싱 (Java 1.5부터)
Java 1.5부터는 컴파일러가 자동으로 박싱과 언박싱을 처리해줍니다.
// 오토박싱: int → Integer
Integer num1 = 100; // 컴파일러가 Integer.valueOf(100)으로 변환
// 오토언박싱: Integer → int
Integer num2 = 200;
int result = num2; // 컴파일러가 num2.intValue()로 변환
// 컬렉션에서의 오토박싱
List<Integer> list = new ArrayList<>();
list.add(50); // 오토박싱 발생
int value = list.get(0); // 오토언박싱 발생
컴파일러가 내부적으로 변환하는 코드
// 개발자가 작성한 코드
List<Integer> list = new ArrayList<>();
for (int i = 1; i < 50; i += 2) {
list.add(i);
}
// 컴파일러가 실제로 생성하는 코드
List<Integer> list = new ArrayList<>();
for (int i = 1; i < 50; i += 2) {
list.add(Integer.valueOf(i)); // 오토박싱
}래퍼 클래스의 주요 메서드들
래퍼 클래스는 다양한 유용한 메서드들을 제공합니다.
// valueOf() - 래퍼 객체 생성
Integer num1 = Integer.valueOf(100); // 숫자로부터
Integer num2 = Integer.valueOf("200"); // 문자열로부터
// parseInt() - 문자열을 기본형으로 변환
int parsed = Integer.parseInt("300");
double d = Double.parseDouble("3.14");
// 비교 메서드
Integer a = 100;
Integer b = 200;
int compareResult = a.compareTo(b); // -1 (a < b)
// 유틸리티 메서드
int sum = Integer.sum(10, 20); // 30
int max = Integer.max(15, 25); // 25
int min = Integer.min(15, 25); // 15
// 문자열 변환
String str = Integer.toString(500);
valueOf()와 parseInt()의 차이점
valueOf("10"): 래퍼 타입(Integer) 반환parseInt("10"): 기본형(int) 반환
성능 차이와 주의사항
이 부분이 실무에서 정말 중요합니다. 실제 성능 테스트 결과를 보면 차이가 상당히 큽니다.
public class PerformanceTest {
public static void main(String[] args) {
int iterations = 1_000_000_000; // 10억 번 연산
// 기본형 테스트
long startTime = System.currentTimeMillis();
long sumPrimitive = 0;
for (int i = 0; i < iterations; i++) {
sumPrimitive += i; // 직접 연산
}
long primitiveTime = System.currentTimeMillis() - startTime;
// 래퍼 클래스 테스트
startTime = System.currentTimeMillis();
Long sumWrapper = 0L;
for (int i = 0; i < iterations; i++) {
sumWrapper += i; // 오토박싱/언박싱 발생
}
long wrapperTime = System.currentTimeMillis() - startTime;
System.out.println("기본형 실행 시간: " + primitiveTime + "ms");
System.out.println("래퍼 클래스 실행 시간: " + wrapperTime + "ms");
System.out.println("성능 차이: " + (wrapperTime / (double)primitiveTime) + "배");
}
}
실제 테스트 결과에 따르면 래퍼 클래스가 기본형보다 수 배에서 수십 배까지 느릴 수 있습니다.
Integer 캐싱 특성
Java는 -128부터 127까지의 Integer 객체를 캐싱합니다. 이는 메모리 최적화를 위한 것이죠.
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true (같은 캐시된 객체)
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false (각각 다른 새로운 객체)
// 올바른 비교 방법
System.out.println(c.equals(d)); // true
NullPointerException 주의사항
래퍼 클래스를 사용할 때 가장 조심해야 할 부분입니다.
Integer nullInteger = null;
int result = nullInteger; // NullPointerException 발생!
// 안전한 처리 방법
Integer userInput = getUserInput(); // null일 수 있음
if (userInput != null) {
int value = userInput; // 안전한 언박싱
// 로직 수행
} else {
// null 처리 로직
}실무에서의 올바른 사용법
지금까지 학습한 내용을 바탕으로 실무에서 어떻게 적용하면 좋을지 정리해보겠습니다.
1. 메서드 매개변수에서의 선택
// 좋은 예: 기본형 사용 (null이 불가능한 값)
public int calculateAge(int birthYear, int currentYear) {
return currentYear - birthYear;
}
// 좋은 예: 래퍼 클래스 사용 (null 가능성이 있는 값)
public String formatUserAge(Integer age) {
if (age == null) {
return "나이 정보 없음";
}
return age + "세";
}
2. 컬렉션에서의 사용
// 필수적으로 래퍼 클래스 사용
Map<String, Integer> scoreMap = new HashMap<>();
scoreMap.put("수학", 95);
scoreMap.put("영어", 88);
// 성능이 중요한 대량 데이터 처리시엔 기본형 배열 고려
int[] scores = new int[1000000]; // 메모리 효율적
// vs
List<Integer> scoreList = new ArrayList<>(); // 유연하지만 메모리 사용량 많음
3. null 처리가 필요한 경우
public class UserService {
// 옵션 값은 래퍼 클래스로
private Integer maxRetryCount; // null이면 무제한
// 필수 값은 기본형으로
private int timeoutSeconds = 30;
public void processUser(Long userId) { // null 체크 필요
if (userId == null) {
throw new IllegalArgumentException("사용자 ID는 필수입니다");
}
// 처리 로직
}
}기본 자료형과 래퍼 클래스는 Java 프로그래밍의 기초이지만, 올바르게 사용하기 위해서는 각각의 특성을 정확히 이해해야 합니다. 성능이 중요한 연산에는 기본형을, 객체의 특성이 필요한 곳에는 래퍼 클래스를 사용하는 것이 핵심입니다.
특히 오토박싱과 언박싱은 편리하지만 성능에 영향을 줄 수 있으므로, 대용량 데이터를 처리하거나 반복 연산이 많은 코드에서는 더욱 주의깊게 사용해야 합니다. 또한 래퍼 클래스 사용 시 NullPointerException을 피하기 위한 적절한 null 체크도 잊지 말아야겠죠.
이런 기본기를 탄탄히 다져두면 더 복잡한 Java 개념들도 훨씬 쉽게 이해할 수 있을 것입니다. 여러분도 실제 코드를 작성할 때 이번 내용을 참고해서 적절한 타입을 선택해보세요!
Java 완전정복! 변수 스코프, final, 상수 패턴 한 번에 이해하기
Java를 공부하다 보면 변수를 사용할 때 헷갈리는 부분들이 많죠? 특히 변수가 어디서부터 어디까지 사용 가능한지(스코프), final 키워드를 언제 써야 하는지, 그리고 상수를 만들 때 클래스를 쓸
byteandbit.tistory.com
'JAVA' 카테고리의 다른 글
| [완벽 가이드] Java 연산자 종류와 우선순위 총정리 – 산술·비트·논리·비교·삼항 연산자 (0) | 2025.09.25 |
|---|---|
| 자바 표준 입력·출력 완전 정복: Scanner와 System.out 활용 가이드 (0) | 2025.09.24 |
| Java 완전정복! 변수 스코프, final, 상수 패턴 한 번에 이해하기 (0) | 2025.09.22 |
| Java 식별자, 키워드, 주석, 코드 스타일 기본 규칙 완벽 가이드 (0) | 2025.09.21 |
| 자바 프로젝트 구조 완벽 가이드: 소스에서 바이너리까지 빌드 흐름 쉽게 이해하기 (0) | 2025.09.20 |