Java/강의

[📙 Java 문법 종합반] 2-3. 래퍼클래스(기본형 참조형)

가지코딩 2025. 4. 15. 16:53

📙 목차

  1. 래퍼클래스(Wrapper Class)란?
  2. 기본형(Primitive Type)
  3. 참조형(Reference Type)
  4. 왜 래퍼클래스를 사용할까?
  5. 오토박싱 vs 언박싱
  6. 기본형과 래퍼형 성능 비교
  7. 실습 과제

🧡 학습 목표

  • 래퍼클래스가 무엇인지 학습한다.
  • 기본형과 참조형이 무엇인지 학습한다.

1. 래퍼클래스(Wrapper Class)란?

래퍼클래스

기본자료형 을 객체로 감싸는 클래스

 

기본 자료형 (Primitive Type) 래퍼 클래스 (Wrapper Class)


2. 기본형(Primitive Type)

자료형 종류 범위 바이트 비트
boolean 논리형 true/false 1 8
char 문자형 0 ~ 65535 유니코드 값 2 16
byte 정수형 -128 ~ 127 1 8
short 정수형 -32,768 ~ 32,767 2 16
int 정수형 -2,147,483,648 ~ 2,147,483,647 4 32
long 정수형 -9,233,372,036,854,775,808 ~
9,233,372,036,854,775,807
8 64
float 실수형 약 소수점 6~7자리까지 4 32
double 실수형 약 소수점 15~17자리까지 8 64

3. 참조형(Reference Type)

  • 변수에 객체가 담기면 해당 변수를 참조형 변수라고 한다. 
  • 참조형 변수는 데이터가 저장된 메모리 주소를 가리킨다. → Heap 메모리 주소
  • 객체 데이터는 Heap 영역에 저장되어 있기 때문이다.
  • 객체, 배열등이 참조형에 속한다.
Person personA = new Person("Steve"); // ✅ 객체가  담긴 personA 는 참조형 변수입니다.
Syetem.out.println(personA.name);
System.out.println(personA); // ✅ 출력하면 @123 메모리의 주소값이 출력됩니다.
int[] arr = {1, 2, 3, 4}; // ✅ 배열이 담긴 arr 는 참조형 변수입니다.
System.out.println(arr); // ✅ 출력하면 @123 메모리의 주소값이 출력됩니다.

 

 

래퍼클래스도 객체이다.

  • 래퍼클래스가 담겨 있는 변수도 참조형 변수이다.
  • 내부적으로toString()이 오버라이딩되어 있기 때문에, 출력시 메모리 주소값이 나오지 않는다.
Integer num = 100;
System.out.println(num); // 출력 100

4. 왜 래퍼클래스를 사용할까?

  • 기본형은 객체처럼 속성, 기능을 가질 수 없다.
  • 기본형을 감싼 객체를 만들어 기능을 제공하면 편리하게 데이터처리를 할 수 있다.
Integer num = 123; // 래퍼클래스
String str = num.toString(); // ✅ 편리한 기능

int a = 100; // 그냥 데이터 100
String str = a.toString(); // ❌ 변환 불가

5. 오토박싱 vs 언박싱

  • 래퍼클래스 ↔ 기본형 형변환
  • Java에서는 이 형변환 과정을 자동으로 지원해준다.

 

오토박싱(Auto-boxing)

  • 기본형 → 래퍼형으로 변환하는 과정
Integer num3 = 10; // ✅ 오토박싱

// ✅ 내부적 자동 처리(래퍼형 <- 기본형)
Integer num = Integer.valueOf(10);

 

 

오토 언박싱

  • 래퍼형 → 기본형으로 변환하는 과정
Integer num3 = 10; 
int num = num3;   // ✅ 오토 언박싱

// ✅ 내부적 자동처리(기본형 <- 래퍼형)
int a = num.intValue();

6. 기본형과 래퍼형 성능 비교

  • 기본형보다 래퍼클래스는 연산 속도가 느리다.
    • 래퍼형은 내부적으로 데이터를 감싸고 있기때문에 연산시 불리하다.
    • 객체에서 기본형 값을 꺼내서 연산하는 추가작업이 발생한다.
  • 빠른 작업이 필요한 경우 기본형을 직접 활용하는 것이 좋다.

 

성능 테스트

더보기
public class PrimitiveVsWrapperPerformance {
    public static void main(String[] args) {
        int iteration = 10_000_000; // 1000만 번 반복
        
        // 기본형 int 연산 성능 테스트
        long startTime1 = System.nanoTime();
        int sum1 = 0;
        for (int i = 0; i < iteration; i++) {
            sum1 += i;  // 기본형 연산
        }
        long endTime1 = System.nanoTime();
        long primitiveTime = endTime1 - startTime1;

        // 래퍼 클래스 Integer 연산 성능 테스트
        long startTime2 = System.nanoTime();
        Integer sum2 = 0;
        for (int i = 0; i < iteration; i++) {
            sum2 += i;  // 오토박싱 & 언박싱 발생
        }
        long endTime2 = System.nanoTime();
        long wrapperTime = endTime2 - startTime2;

        // 결과 출력
        System.out.println("기본형(int) 연산 시간: " + primitiveTime + " ns");
        System.out.println("래퍼 클래스(Integer) 연산 시간: " + wrapperTime + " ns");
        System.out.println("성능 차이 (배수): " + (double) wrapperTime / primitiveTime);
    }
}

 

 

실행 결과: 래퍼형이 기본형보다 13배 느리게 동작한다.


7. 실습 과제

double 기본형과 직접만든 MyDouble 래퍼형의 연산 성능차이 확인하기

 

정답 (강의자료 가져왔다....😂)

// 직접 만든 Double 래퍼 클래스
class MyDouble {
    private final double value;

    public MyDouble(double value) {
        this.value = value;
    }

    public double getValue() {
        return value;
    }

    // 덧셈
    public MyDouble add(MyDouble other) {
        return new MyDouble(this.value + other.value);
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }
}
public class DoubleWrapperPerformance {
    public static void main(String[] args) {
        int iteration = 10_000_000; // 1000만 번 반복

        // 1. 기본형 double 연산
        long startTime1 = System.nanoTime();
        double sum1 = 0.0;
        for (int i = 0; i < iteration; i++) {
            sum1 += i * 1.1;
        }
        long endTime1 = System.nanoTime();
        long primitiveTime = endTime1 - startTime1;

        // 2. MyDouble 연산
        long startTime3 = System.nanoTime();
        MyDouble sum3 = new MyDouble(0.0);
        for (int i = 0; i < iteration; i++) {
            sum3 = sum3.add(new MyDouble(i * 1.1));
        }
        long endTime3 = System.nanoTime();
        long myDoubleTime = endTime3 - startTime3;

        // 결과 출력
        System.out.println("기본형(double) 연산 시간: " + primitiveTime + " ns");
        System.out.println("MyDouble 클래스 연산 시간: " + myDoubleTime + " ns");
        System.out.println("MyDouble vs double 성능 차이: " + (double) myDoubleTime / primitiveTime);
    }
}