본문 바로가기
스파르타 내일배움캠프/TIL(Today I learned)

25.02.28 TIL - Wrapper Class, static, final, Interface

by pandastic 2025. 2. 28.
반응형

 

 

목차

     

     

    1. Chapter 2 - 3 : 래퍼클래스(기본형, 참조형)

    1. 래퍼클래스(Wrapper Class)

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

     

     

    기본 자료형 (Primitive Type)  래퍼 클래스 (Wrapper Class)
    byte Byte
    short Short
    int Integer
    long Long
    float Float
    double Double
    char Character
    boolean Boolean

     

     

    2. 참조형(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 메모리의 주소값이 출력됩니다.

     

     - 래퍼클래스가 담겨 있는 변수도 참조형 변수.

        BUT 출력 시 메모리 주소값이 나오지 않음. → 내부적으로 toString()이 오버라이딩 되어있음.

    Integer num = 100;
    System.out.println(num); // 출력 100

     

     

    🤓 오버라이딩(Overriding)

     - 부모 클래스에 정의된 메서드를 자식 클래스에서 새롭게 정의하는 것.

       매개변수와 리턴 타입이 같아야 함.(= 정적 다형성).

      → 기존에 부모 클래스에서 정의한 메서드가 아닌,

           자식 클래스에서 새롭게 정의한 메서드가 실행된다.

     

     

    래퍼 클래스를 사용하는 이유

     - 기본 자료형은 객체처럼 속성, 기능을 가질 수 없음.

     - 객체는 기능을 가질 수 있음 → 기본형을 감싼 객체를 만들어서 기능을 제공하면 편리하게 데이터 처리 가능.

    Integer num = 123; // 래퍼클래스
    String str = num.toString(); // ✅ 편리한 기능
    int a = 100; // 그냥 데이터 100
    String str = a.toString(); // ❌ 변환 불가

     - 래퍼클래스는 객체기 때문에 기능 부분을 활용할 수 있음.

     

     

    * Wrapper 클래스는 객체이기 때문에 다양한 편리 기능을 미리 내부적으로 정의해둠.

      → 기능 중에 하나가 toString()

      → toString()은 정수형 데이터를 문자열 데이터로 바꾸어주는 역할을 함.

    Integer num = 200;
    String num2 = num.toString();

     

     

    오토박싱 vs 언박싱

     - 래퍼 클래스 ↔ 기본형으로 형변환이 굉장히 자주 일어남.

     - Java에서는 형변환 과정을 자동으로 지원.

    Integer num3 = 10; // 오토박싱 (기본형을 자동으로 래퍼 클래스 객체로 변환)
    int num = num3;   // 오토 언박싱(참조형을 자동으로 기본형으로 변환)

     

    오토박싱(Auto-boxing)

     - 기본형 → 래퍼형 으로 변환하는 과정.

     - Integer는 참조형(객체)이지만 기본형 int값을 직접 대입할 수 있음.

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

      - 내부적으로는 valueOf()를 사용하여 자동처리하는 것이다.

     

     

    오토 언박싱(Auto-Unboxing)

      - 래퍼형 → 기본형으로 변환하는 과정.

      - num은 Integer 객체지만 기본형 int 변수에 대입 가능.

    Integer num3 = 10; 
    int num = num3;   // ✅ 오토 언박싱
    
    // ✅ 내부적 자동처리(기본형 <- 래퍼형)
    int a = num.intValue();

      - 내부적으로 컴파일러가 num.intValue()를 호출하여 기본형으로 변환하기 때문.

     

    기본형과 래퍼형 성능 비교

      - 래퍼형은 내부적으로 데이터를 감싸고 있기 때문에 연산 시 불리함.

        →  객체에서 기본형 값을 꺼내서 연산하는 추가작업이 발생하기 때문.

      - 빠른 작업이 필요한 경우 기본형을 직접 활용하는 것이 좋은 선택.

     

    [퀴즈]

    더보기

    Q1. 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);
        }
    }

     

     

    2. Chapter 2 - 4 : static - 클래스가 공유하는 공간

    1. Static

       - 모든 객체가 함께 사용하는 변수나 메서드를 만들 때 사용됨.

       - 객체(인스턴스)를 만들지 않아도 클래스 이름만으로 바로 사용 가능.

       - 모든 객체가 같은 값 공유.

       - static 변수와 메서드는 실행 시점에 한 번만 생성되고 Method Area에 저장됨.

     

     

    Static 활용

      - static은 변수, 메서드에 붙일 수 있음.

      - static 키워드로 선언된 변수와 메서드는 Method Area에 저장됨.

      - 각 객체(인스턴스)는 클래스 영역에 저장된 데이터 활용 가능.

     

     

    public class Person {
        // static 변수
        static int population = 0;
        // static 메서드
        static void printPopulation() {
            System.out.println("현재 인구 수 : " + population);
        }
    }
    public class Main {
        public static void main(String[] args) {
            // 객체(Person person = new Person()) 를 따로 생성할 필요 없이
            // Class 레벨을 통해 접근하여 바로 사용 가능.
            // 프로그램 시작 시점에 Method Area에 올라가 있기 때문에 가능함.
            System.out.println("static 변수 활용 : " + Person.population);
            Person.printPopulation();
        }
    }

     - 객체( Person person = new Person( ) )를 따로 생성할 필요 없이 Class 레벨을 통해 접근하여 바로 사용 가능.

     - 프로그램 시작 시점에 Method Area에 올라가 있기 때문에 가능함.

     

     

    2. 인스턴스 멤버

      - 객체를 만들 때마다 생성되는 변수와 메서드.

      - 객체(인스턴스)를 생성한 후에만 사용 가능.

      - 각 객체가 개별적으로 값을 가짐(공유되지 않음!!)

      - 인스턴스는 Heap Area 에 위치함.

     

     

    1. 인스턴스 변수

      - 객체가 생성될 때마다 따로 만들어지는 변수.

      - 객체를 생성한 후 접근할 수 있음.

      - name 변수는 각 객체마다 별도로 저장됨.

     

     

    2. 인스턴스 메서드

      - 객체의 속성을 활용하는 메서드.

      - 객체가 생성된 후에만 사용 가능.

     

     

    3. 클래스 멤버

      - 클래스 자체에 속하는 변수와 메서드.

      - static 키워드를 사용하여 선언.

     

     

    1. 클래스 변수

      - 클래스가 로드될 때 한 번만 생성됨.

      - 모든 객체가 공유하는 변수.

      - Heap이 아니라 Method Area에 저장됨.

      - 객체를 만들지 않아도 클래스명.변수명 으로 접근 가능.

     

     

    2. 클래스 메서드

      - 클래스에 속하는 메서드.

      - 객체 없이 사용 가능.

      - 클래스 변수만 사용할 수 있고 인스턴스 변수는 사용할 수 없음.

     

     

    [Static 사용 시 주의사항]

    클래스 변수 사용 시 주의 사항

      - Static은 공유가 필요한 곳에 사용해야함

         → 모든 객체가 동일한 이름을 공유하게 됨. 나중에 선언된 이름으로 덮어씌워져 공용으로 활용됨.

     

    Static 메서드에서 인스턴스 변수에 접근.

      - Static 메서드에서는 인스턴스 변수에 접근할 수 없음.

      - 인스턴스 멤버를 사용하기 위해서는 먼저 객체가 생성되어야 함.

      - 객체 없이 사용할 수 없음. 접근도 안됨!!

     

    public class Person {
        // 인스턴스 변수
        String name;
        // static 변수
        static int population = 0;
        Person(){
            population++;
        }
        // 인스턴스 메서드
        void printName(){
            System.out.println("나의 이름은 " + this.name + "입니다.");
        }
        // static 메서드
        static void printPopulation() {
            Person p3 = new Person();
            System.out.println(p3.name);
            System.out.println("현재 인구 수 : " + population);
        }
    }

      - Static 메서드에 Person p3 = new Person() 처럼 객체 생성을 해줘야함!!!

     

     

    ‼️Static은 꼭 필요할 때만 사용해야함!!

      - Static 변수와 메모리는 프로그램이 종료될 때까지 메모리에 유지됨.

        → Static 변수는 Method Area에 올라가는데

            Method Area는 프로그램 시작 시점에 메모리에 탑재되어 종료될 때까지 유지되기 때문.

      - 모든 변수의 static을 활용하게 되면 메모리가 많이 필요한 프로그램이 되어버림.

        → 너무 많은 static을 남용하면 메모리 낭비로 이어짐.

     

     

     

     

    반응형