처음부터 차근차근

[Java] Wrapper Class 본문

Language/Java

[Java] Wrapper Class

HangJu_95 2024. 7. 31. 23:13
728x90

Wrapper Class란??

Wrapper Class란 기본형을 객체로 감싸서 더 편리하게 사용하도록 도와주는 클래스이다. 즉, 기본형의 객체 버전이다.
실제 현업에서도 기본형보다는 래퍼 클래스를 많이 사용한다.

  • byte -> Byte
  • short-> Short
  • int -> Integer
  • long -> Long
  • float -> Float
  • double -> Double
  • char -> Character
  • boolean -> Boolean

기본 래퍼 클래스는 다음과 같은 특징을 가지고 있다.

  • 불변이다
  • equals로 비교해야 한다.

간단한 예시를 통해 사용해보자.

package lang.wrapper;

public class WrapperClassMain {
    public static void main(String[] args) {
        Integer newInteger = new Integer(10); // 삭제 예정이다.
        Integer integerObj = Integer.valueOf(10); //-128 ~ 127 자주 사용하는 숫자 값 재사용, 불변
        Long longObj = Long.valueOf(100);
        Double doubleObj = Double.valueOf(10.5);

        System.out.println("newInteger = " + newInteger);
        System.out.println("integerObj = " + integerObj);
        System.out.println("longObj = " + longObj);
        System.out.println("doubleObj = " + doubleObj);

        System.out.println("내부 값 읽기");
        int intValue = integerObj.intValue();
        System.out.println("intValue = " + intValue);
        long longValue = longObj.longValue();
        System.out.println("longValue = " + longValue);

        System.out.println("비교");
        System.out.println("==: " + (newInteger == integerObj)); // false
        System.out.println("equals: " + newInteger.equals(integerObj)); // true

        // Integer는 ~128에서 127 범위를 미리 생성해준다.
        Integer Integer1 = Integer.valueOf(10);
        System.out.println("==: " + (integerObj == Integer1)); // true

    }
}

래퍼 클래스 생성을 boxing이라고 한다.

  • 기본형을 래퍼 클래스로 변경하는 것을 마치 박스에 물건을 넣은 것 같다고 해서 박싱이라 한다.
  • Integer에는 성능 최적화 기능이 있다. ~128에서 127 범위를 미리 생성해준다. 해당 범위 값을 조회하면 미리 생성된 Integer 객체를 반환한다. 해당 범위 값이 없으면 new Integer()를 호출한다.

intValue() - unboxing

  • 래퍼 클래스에 들어있는 기본형 값을 다시 꺼내는 메서드이며, 박스에 들어있는 물건을 꺼내는 것 같다고 해서 언박싱이라 한다.

비교는 equals()를 사용한다.

  • 래퍼 클래스는 객체이기 때문에 == 비교를 하면 인스턴스의 참조값을 비교한다.
  • 따라서 내부의 값을 비교하기 위해 equals를 재정의 해두었다.

참고로 래퍼 클래스는 객체를 그대로 출력해도 내부에 있는 값을 문자로 출력하도록 toString() 을 재정의했다.

왜 wrapper가 만들어졌을까?

자바는 객체지향 언어이다. 그런데 자바 안에 객체가 아닌 것으로 기본형 타입이 있다.
기본형은 객체가 아니기 때문에 다음과 같은 한계가 존재한다.

  • 객체가 아님 : 기본형 데이터는 객체가 아니기 때문에, 객체 지향 프로그래밍의 장점을 살릴 수 없다. 예를 들어 객체는 유용한 메서드를 제공할 수 있지만, 기본형은 객체가 아니므로 메서드를 제공할 수 없다.
  • null값을 가질 수 없음 : 기본형 데이터 타입은 null 값을 가질 수 없다. 때로는 데이터가 없음 이라는 상태를 나타내야 할 필요가 있는데, 기본형은 항상 값을 가지기 때문에 이런 표현을 할 수 없다.

Wrapper Class - autoBoxing

자바에서는 오토 박싱, 오토 언박싱을 지원한다.

package lang.wrapper;

public class AutoboxingMain2 {
    public static void main(String[] args) {
        // Primitive -> Wrapper
        int value = 7;
        Integer boxedValue = value;

        // Wrapper -> Primitive
        int unboxedValue = boxedValue;

        System.out.println("boxedValue = " + boxedValue);
        System.out.println("unboxedValue = " + unboxedValue);
    }
}

원래였다면, valueOf를 통해 boxing해야 하고, intValue()를 통해 unboxing을 해야 하지만, 매번 사용하면 불편하기에 자바에서 자동으로 지원하도록 설정해줬다.

Wrapper Class - 주요 메서드

Integer를 자주 사용하는데, 메서드를 알아보자.

  • valueOf() : 래퍼 타입을 반환한다. 숫자, 문자열을 모두 지원한다.
  • parseInt() : 문자열을 기본형으로 변환한다.
  • compareTo() : 내 값과 인수로 넘어온 값을 비교한다. 내 값이 크면 1 , 같으면 0 , 내 값이 작으면 -1 을 반환한다.
  • Integer.sum() , Integer.min() , Integer.max() : static 메서드이다. 간단한 덧셈, 작은 값, 큰 값 연산을 수행한다.

Wrapper Class의 성능

래퍼 클래스는 객체이기 때문에 기본형보다 다양한 기능을 제공한다.
하지만 객체이기 때문에 기본형보다 많은 메모리를 차지한다.

  • CPU 연산을 아주 많이 수행하는 특수한 경우이거나, 수만~ 수십만 이상 연속해서 연산을 수행해야 하는 경우라면 기본형을 사용해서 최적화를 고려하자.
  • 그렇지 않은 일반적인 경우라면 코드를 유지보수하기 더 나은 것을 선택하면 된다.

참고 : 유지보수 vs 최적화
유지보수 vs 최적화를 고려해야 하는 상황이라면 유지보수하기 좋은 코드를 먼저 고민해야 한다. 특히 최신 컴퓨터는 매우 빠르기 때문에 메모리 상에서 발생하는 연산을 몇 번 줄인다고해도 실질적인 도움이 되지 않는 경우가 많다.

  • 코드 변경 없이 성능 최적화를 하면 가장 좋겠지만, 성능 최적화는 대부분 단순함 보다는 복잡함을 요구하고, 더 많은 코드들을 추가로 만들어야 한다. 최적화를 위해 유지보수 해야 하는 코드가 더 늘어나는 것이다. 그런데 진짜 문제는 최적화를 한다고 했지만 전체 애플리케이션의 성능 관점에서 보면 불필요한 최적화를 할 가능성이 있다.
  • 특히 웹 애플리케이션의 경우 메모리 안에서 발생하는 연산 하나보다 네트워크 호출 한 번이 많게는 수십만배 더 오래 걸린다. 자바 메모리 내부에서 발생하는 연산을 수천번에서 한 번으로 줄이는 것 보다, 네트워크 호출 한 번을 더 줄이는 것이 더 효과적인 경우가 많다.
  • 권장하는 방법은 개발 이후에 성능 테스트를 해보고 정말 문제가 되는 부분을 찾아서 최적화 하는 것이다.

Class 클래스

지바에서 Class 클래스의 정보(메타데이터)를 다루는데 사용된다. Class 클래스를 통해 개발자는 실행 중인 자바 애플리케이션 내에서 필요한 클래스의 속성과 메서드에 대한 정보를 조회하고 조작할 수 있다.

Class 클래스의 주요 기능은 다음과 같다.

  • 타입 정보 얻기: 클래스의 이름, 슈퍼클래스, 인터페이스, 접근 제한자 등과 같은 정보를 조회할 수 있다.
  • 리플렉션: 클래스에 정의된 메서드, 필드, 생성자 등을 조회하고, 이들을 통해 객체 인스턴스를 생성하거나 메서드를 호출하는 등의 작업을 할 수 있다.
  • 동적 로딩과 생성: Class.forName() 메서드를 사용하여 클래스를 동적으로 로드하고, newInstance()메서드를 통해 새로운 인스턴스를 생성할 수 있다.
  • 애노테이션 처리: 클래스에 적용된 애노테이션(annotation)을 조회하고 처리하는 기능을 제공한다.
package lang.clazz;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ClassMetaMain {
    public static void main(String[] args) throws Exception {
        // Class 조회
        Class clazz = String.class; // 1. 클래스에서 조회
//        Class clazz = new String().getClass(); // 2. 인스턴스에서 조회
//        Class clazz = Class.forName("java.lang.String");// 3. 문자열로 조회

        // 모든 필드 출력
        Field[] fields = clazz.getDeclaredFields();
//        for (Field field : fields) {
//            System.out.println("field = " + field);
//        }
        for (Field field : fields) {
            System.out.println("Field: " + field.getType() + " " + field.getName());
        }

        // 모든 메서드 출력
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("Method: " + method);
        }

        // 상위 클래스 정보 출력
        System.out.println("Superclass: " + clazz.getSuperclass().getName());
        // 인터페이스 정보 출력
        Class[] interfaces = clazz.getInterfaces();
        for (Class i : interfaces) {
            System.out.println("Interface: " + i.getName());
        }
    }
}

class 클래스의 주요 메서드로는

  • getDeclaredFields(): 클래스의 모든 필드를 조회한다.
  • getDeclaredMethods(): 클래스의 모든 메서드를 조회한다.
  • getSuperclass(): 클래스의 부모 클래스를 조회한다.
  • getInterfaces(): 클래스의 인터페이스들을 조회한다.

Class 생성하기

Class 클래스에는 클래스의 모든 정보가 들어있다. 이 정보를 기반으로 인스턴스를 생성하거나, 메서드를 호출하고 필드의 값도 변경할 수 있다.

package lang.clazz;

public class ClassCreateMain {
    public static void main(String[] args) throws Exception {
//        Class helloClass = Hello.class;
        Class helloClass = Class.forName("lang.clazz.Hello");
        Hello hello = (Hello) helloClass.getDeclaredConstructor().newInstance();
        String result = hello.hello();
        System.out.println("result = " + result);
    }
}
  • getDeclaredConstructor() : 생성자를 선택한다.
  • newInstance() : 선택된 생성자를 기반으로 인스턴스를 생성한다.

System Class

System 클래스는 시스템과 관련된 기본 기능을 제공한다.

  • 표준 입력, 출력, 오류 스트림: System.in , System.out , System.err 은 각각 표준 입력, 표준 출력, 표준 오류 스트림을 나타낸다.
  • 시간 측정: System.currentTimeMillis()System.nanoTime() 은 현재 시간을 밀리초 또는 나노초 단위로 제공한다.
  • 환경 변수: System.getenv() 메서드를 사용하여 OS에서 설정한 환경 변수의 값을 얻을 수 있다.
  • 시스템 속성: System.getProperties() 를 사용해 현재 시스템 속성을 얻거나 System.getProperty(String key) 로 특정 속성을 얻을 수 있다. 시스템 속성은 자바에서 사용하는 설정값이다.
  • 시스템 종료: System.exit(int status) 메서드는 프로그램을 종료하고, OS에 프로그램 종료의 상태 코드를 전달한다.
  • 상태 코드 0 : 정상 종료
  • 상태 코드 0 이 아님: 오류나 예외적인 종료
  • 배열 고속 복사: System.arraycopy 는 시스템 레벨에서 최적화된 메모리 복사 연산을 사용한다. 직접 반복문을 사용해서 배열을 복사할 때 보다 수 배 이상 빠른 성능을 제공한다.

Math 클래스

Math는 수 많은 수학 문제를 해결해주는 클래스다.

  1. 기본 연산 메서드
    abs(x) : 절대값
    max(a, b) : 최대값
    min(a, b) : 최소값
  2. 지수 및 로그 연산 메서드
    exp(x) : e^x 계산
    log(x) : 자연 로그
    log10(x) : 로그 10
    pow(a, b) : a의 b 제곱
  3. 반올림 및 정밀도 메서드
    ceil(x) : 올림
    floor(x) : 내림
    rint(x) : 가장 가까운 정수로 반올림
    round(x) : 반올림
  4. 삼각 함수 메서드
    sin(x) : 사인
    cos(x) : 코사인
    tan(x) : 탄젠트
  5. 기타 유용한 메서드
    sqrt(x) : 제곱근
    cbrt(x) : 세제곱근
    random() : 0.0과 1.0 사이의 무작위 값 생성

Random 클래스

랜덤인 경우 Math.random()을 사용해도 되지만, Random 클래스를 사용하면 더욱 다양한 랜덤값을 구할 수 있다.

package lang.math;

import java.util.Random;

public class RandomMain {
    public static void main(String[] args) {
        Random random = new Random();
        //Random random = new Random(1); //seed가 같으면 Random의 결과가 같다.
        // 랜덤은 내부에서 Seed값을 사용해서 랜덤 값을 구한다.
        // Seed 값이 같으면 항상 같은 결과를 출력한다.

        int randomInt = random.nextInt(); // 랜덤 `int` 값을 반환한다.
        System.out.println("randomInt: " + randomInt);

        double randomDouble = random.nextDouble(); //0.0d ~ 1.0d
        System.out.println("randomDouble: " + randomDouble);

        boolean randomBoolean = random.nextBoolean();
        System.out.println("randomBoolean: " + randomBoolean);

        // 범위 조회
        int randomRange1 = random.nextInt(10); //0 ~ 9까지 출력
        System.out.println("0 ~ 9: " + randomRange1);

        int randomRange2 = random.nextInt(10) + 1; //1 ~ 10까지 출력
        System.out.println("1 ~ 10: " + randomRange2);
    }
}

Random을 생성할 때, 내부의 시드 값을 설정할 수 있으며, Seed 값을 사용해서 랜덤 값을 구한다.
Seed 값이 같으면 항상 같은 결과를 출력한다.

  • new Random() : 생성자를 비워두면 내부에서 System.nanoTime() 에 여러가지 복잡한 알고리즘을 섞어서 씨드값을 생성한다. 따라서 반복 실행해도 결과가 항상 달라진다.
  • new Random(int seed) : 생성자에 씨드 값을 직접 전달할 수 있다. 씨드 값이 같으면 여러번 반복 실행해도 실행 결과가 같다. 이렇게 씨드 값을 직접 사용하면 결과 값이 항상 같기 때문에 결과가 달라지는 랜덤 값을 구할 수 없다. 하지만 결과가 고정되기 때문에 테스트 코드 같은 곳에서 같은 결과를 검증할 수 있다.
  • random.nextInt() : 랜덤 int 값을 반환한다.
  • nextDouble() : 0.0d ~ 1.0d 사이의 랜덤 double 값을 반환한다.
  • nextBoolean() : 랜덤 boolean 값을 반환한다.
  • nextInt(int bound) : 0 ~ bound 미만의 숫자를 랜덤으로 반환한다. 예를 들어서 3을 입력하면 0, 1, 2 를 반환한다.

참고

 

김영한의 실전 자바 - 중급 1편 강의 | 김영한 - 인프런

김영한 | 실무에 필요한 자바의 다양한 중급 기능을 예제 코드로 깊이있게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문법을

www.inflearn.com

 

'Language > Java' 카테고리의 다른 글

[Java] 날짜와 시간  (4) 2024.08.27
[Java] Enum  (0) 2024.08.09
[Java] String 클래스  (0) 2024.07.31
[Java] 불변 객체  (0) 2024.07.26
[Java] Object 클래스  (0) 2024.07.24