JAVA

자바 래퍼 클래스와 날짜 — 기본형을 감싸고 시간을 다루기(WRAPPER·DATE)

PANCO_IT
#자바#JAVA#래퍼클래스#Integer#LocalDate

기본형 int·double·char·boolean을 각각 Integer·Double·Character·Boolean으로 감싸는 포장지 비유 그림

기본형마다 짝이 되는 포장 클래스가 있습니다. 포장하고 푸는 일은 자바가 자동으로 합니다.

지난 편에서 넘어간 숙제가 하나 있습니다. 컬렉션의 꺾쇠에는 int를 못 쓰고 Integer를 써야 한다고 했죠. 그런데 이 Integer는 대체 무엇이고, int와 뭐가 다를까요. 오늘 앞부분에서 이 정체를 밝힙니다. 그리고 뒷부분에서는 모든 프로그램이 결국 만나게 되는 주제, 날짜와 시간을 다룹니다. 시험까지 며칠 남았는지 계산하는 코드를 오늘 직접 돌려 봅니다.

Integer의 정체 — 래퍼 클래스

Integerint 값 하나를 클래스로 감싼 것입니다. 이런 클래스를 래퍼 클래스(Wrapper class)라고 부릅니다. 랩(wrap), 즉 포장한다는 뜻 그대로입니다.

쉽게 — 알사탕(기본형 값)과 포장지에 싼 사탕(래퍼 객체)의 관계입니다. 내용물은 같지만, 포장이 있어야 들어갈 수 있는 자리가 있습니다. 선물 상자(컬렉션)에는 포장된 사탕만 담는 것이죠.

왜 이런 게 필요할까요. 자바의 기본형 8개는 클래스가 아닙니다. 그런데 제네릭과 컬렉션의 타입 자리에는 클래스만 올 수 있습니다. 그래서 자바는 기본형마다 짝이 되는 포장 클래스를 만들어 뒀습니다. intInteger, doubleDouble, charCharacter, booleanBoolean. 나머지도 규칙은 같습니다. 대부분 첫 글자만 대문자로 바뀐 이름이고, intchar만 풀네임이 됩니다.

포장과 풀기는 자동입니다 — 오토박싱

포장을 씌우는 것을 박싱(boxing), 벗기는 것을 언박싱(unboxing)이라고 합니다. 다행히 요즘 자바에서는 이 일을 컴파일러가 알아서 해줍니다.

Integer a = 10;        // int → Integer 자동 포장 (오토박싱)
int b = a + 5;         // Integer → int 자동 풀기 (오토언박싱)

ArrayList<Integer> nums = new ArrayList<>();
nums.add(3);           // int를 넣었지만 자동으로 Integer가 되어 들어감
int first = nums.get(0);  // 꺼낼 때도 자동으로 풀림

지난 편 컬렉션 예제에서 숫자를 그냥 넣고 꺼냈던 것이 바로 오토박싱 덕분이었습니다. 문법이 편해진 만큼 정체를 몰라도 코드는 돌아가지만, 잠시 뒤에 보듯 모른 채 지나가면 당하는 함정이 하나 있습니다.

문자열을 숫자로 — 래퍼의 두 번째 직업

래퍼 클래스는 포장지 역할 말고도 변환 도구 역할을 합니다. 가장 많이 쓰는 것이 문자열을 숫자로 바꾸는 parseInt입니다.

String input = "85";
int score = Integer.parseInt(input);      // "85" → 85
double d = Double.parseDouble("3.14");    // "3.14" → 3.14
String s = String.valueOf(100);           // 100 → "100" (반대 방향)

화면이나 파일에서 읽은 값은 전부 문자열로 들어옵니다. "85" + 15를 계산하면 100이 아니라 "8515"가 되죠. JAVA1에서 배운 문자열 연결입니다. 그래서 계산하려면 먼저 숫자로 바꾸는 이 한 줄이 실무에서 수없이 쓰입니다. 숫자가 아닌 문자열을 넣으면 NumberFormatException이 터진다는 것도 기억해 두세요. 1편에서 배운 try-catch가 필요한 대표 상황입니다.

단골 함정 — ==는 128부터 거짓말을 합니다

여기가 오늘의 함정입니다. 래퍼끼리 ==로 비교하면 이상한 일이 벌어집니다.

Integer a = 127, b = 127;
System.out.println(a == b);      // true

Integer c = 128, d = 128;
System.out.println(c == d);      // false ?!

값은 분명 같은데 127까지는 true, 128부터는 false입니다. 이유는 ==값이 아니라 상자(객체)가 같은 상자인지를 비교하기 때문입니다. 자바는 자주 쓰는 -128~127 범위의 Integer를 미리 만들어 재사용해서, 이 범위에서는 우연히 같은 상자를 가리켜 true가 나옵니다. 128부터는 매번 새 상자를 만들어 false가 되는 것이죠.

==는 상자를 비교해 128부터 false, equals는 값을 비교해 항상 true라는 비교 그림

그림 1. 래퍼끼리 비교할 때는 equals를 씁니다.

해결은 간단합니다. **래퍼의 값 비교는 equals**로 합니다.

System.out.println(c.equals(d));   // true — 값을 비교

작은 수로 테스트할 때는 멀쩡하다가 데이터가 커지면 갑자기 어긋나는, 찾기 고약한 버그의 단골 원인입니다. 기본형 int끼리의 ==는 값 비교라 안전하니, 헷갈리면 "포장지가 붙어 있으면 equals"로 기억하면 됩니다.

날짜 — LocalDate로 오늘을 잡습니다

이제 두 번째 주제입니다. 날짜와 시간은 java.time 패키지의 LocalDate(날짜)와 LocalDateTime(날짜+시각)으로 다룹니다.

import java.time.LocalDate;

LocalDate today = LocalDate.now();              // 오늘
LocalDate exam = LocalDate.of(2026, 11, 19);    // 특정 날짜 만들기

System.out.println(today.getYear());        // 연도만
System.out.println(exam.getDayOfWeek());    // 요일 (THURSDAY)

날짜 계산이 진짜 편리한 부분입니다. 더하고 빼는 메서드가 다 준비되어 있습니다.

LocalDate nextWeek = today.plusDays(7);      // 7일 뒤
LocalDate lastMonth = today.minusMonths(1);  // 한 달 전

한 가지 성질만 주의하세요. plusDays원본을 바꾸지 않고 새 날짜를 돌려줍니다. today.plusDays(7);만 쓰고 결과를 안 받으면 아무 일도 일어나지 않습니다. 반드시 LocalDate d = today.plusDays(7);처럼 받아서 써야 합니다.

두 날짜 사이의 간격은 ChronoUnit으로 구합니다. 디데이 계산이 한 줄입니다.

import java.time.temporal.ChronoUnit;

long dday = ChronoUnit.DAYS.between(today, exam);   // 오늘부터 시험까지 며칠

직접 실행해 보기

오늘 배운 것을 한 번에 돌려 봅니다. 문자열 점수를 숫자로 바꿔 합산하고, 128 함정을 실험하고, 시험 디데이를 계산합니다. exam 날짜를 여러분의 실제 일정으로 바꿔 보세요.

래퍼와 날짜 한 번에 익히기
import java.util.ArrayList;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

public class Main {
  public static void main(String[] args) {
      // 1. 문자열 점수 → 숫자로 바꿔 합산 (parseInt)
      String[] inputs = {"85", "92", "78"};
      ArrayList<Integer> scores = new ArrayList<>();
      int total = 0;
      for (String s : inputs) {
          int n = Integer.parseInt(s);   // 문자열 → 숫자
          scores.add(n);                 // 오토박싱으로 컬렉션에
          total += n;
      }
      System.out.println("합계: " + total);

      // 2. == 함정 실험: 127과 128
      Integer a = 127, b = 127, c = 128, d = 128;
      System.out.println("127==127 → " + (a == b));
      System.out.println("128==128 → " + (c == d));
      System.out.println("equals   → " + c.equals(d));

      // 3. 디데이 계산
      LocalDate today = LocalDate.now();
      LocalDate exam = LocalDate.of(2026, 11, 19);   // 수능일
      long dday = ChronoUnit.DAYS.between(today, exam);
      System.out.println("시험까지 " + dday + "일");
  }
}

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

두 번째 실험의 출력이 그림 1에서 본 그대로 나오는지 확인해 보세요. 같은 128인데 ==false, equalstrue가 나옵니다.

한 장 정리

항목내용
래퍼 클래스기본형을 감싼 클래스 — Integer, Double, Character, Boolean
왜 필요한가컬렉션·제네릭에는 클래스 타입만 올 수 있어서
오토박싱포장·풀기를 컴파일러가 자동 처리
문자열→숫자Integer.parseInt("85") — 실패 시 NumberFormatException
비교 함정래퍼끼리 ==는 상자 비교(128부터 false) → equals 사용
날짜LocalDate.now() · of() · plusDays() — 원본 불변, 결과를 받아서 사용
디데이ChronoUnit.DAYS.between(시작, 끝)

이것만 기억하면 됩니다. 래퍼는 기본형이 클래스 자리에 들어가기 위한 포장지이고, 포장은 자동이지만 비교만은 equals로 해야 합니다. 날짜는 LocalDate가 표준이고, 계산 결과는 늘 새 객체로 돌려받는다는 것만 지키면 디데이 계산까지 한 줄로 끝납니다.

미니 퀴즈

개념을 제대로 잡았는지 직접 풀어 봅니다. 정답은 눌러야 나옵니다.

미니 퀴즈

OX 2문제 + 4지선다 3문제


포켓코딩(JAVA3) 5편 · 다음 편: 파일 입출력 — 파일을 읽고 쓰는 법.

PANCO_IT

IT 지식을 정리하는 개발자

관련 글