- Wrapper Class란 무엇이고, Wrapping을 함으로써 얻는 이점과 일급 콜랙션에 대한 사용 예시를 들며 설명하기
Wrapper Class란
- 자바 API 클래스중 하나이다.
- 자바의 자료형은
primitive type(기본 타입)
과 reference type(참조 타입)
으로 나누어진다.
기본 타입
: byte, short, char, int, long, float, double, boolean
참조 타입
: class, interface ..
- 8개의
기본 타입
에 해당하는 데이터를 객체로 표현하기 위해 포장해 주는 클래스가 바로 wrapper class(래퍼 클래스)
이다.
- 예를 들어, 메소드의 파라미터로 객체 타입만이 요구될 경우
- 기본 타입의 데이터를 그대로 사용할 수 도 있지만 (
AutoBoxing
을 통해 가능해진다.)
- 기본 타입의 데이터를 먼저 객체로 변환후 작업을 수행해야한다.
기본 타입
은 값을 갖는 객체인 포장 객체
를 생성할 수 있다. (기본 타입의 값을 내부에 두고 포장하기때문에 '포장 객체'라 칭한다.)
wrapper class
는 각 타입에 해당하는 데이터를 파라미터로 전달받아, 해당 값을 가지는 객체로 만들어준다.
wrapper class
로 감싸고 있는 기본 타입 값은 외부에서 변경할 수 없다.
- 변경하기 위해서 새로운 포장객체를 만들어야 한다.
Wrapper Class 종류
Wrapper Class 구조
wrapper class
들은 모두 java.lang
패키지에 포함되어 제공된다.
Object
클래스 : 모든 wrapper class
의 부모 클래스
Number
클래스 : 내부적으로 숫자를 다루는 wrapper class
들의 부모 클래스
Boxing & UnBoxing
wrapper class
인스턴스에 저장된 값을 변경할 수 없다. (산술 연산을 위한 클래스가 아니기 때문이다.)
Boxing
: 기본 타입
의 데이터를 -> wrapper class
의 인스턴스로 변환하는 과정
Integer num = new Integer(1);
UnBoxing
: wrapper class
의 인스턴스에 저장된 값
을 -> 기본 타입
의 데이터로 꺼내는 과정
AutoBoxing & AutoUnBoxing
JDK 1.5
부터 boxing
,unboxing
이 필요한 상황에서 자바 컴파일러가 이를 자동으로 처리해준다.
AutoBoxing
: 자동화된 Boxing
AutoUnBoxing
: 자동회된 UnBoxing
예시(Boxing & UnBoxing, AutoBoxing & AutoUnBoxing)
Integer num = new Integer(17);
int n = num.intValue();
Character ch = 'X';
char c = ch;
Wrapper Class 비교연산 (==, equals)
Integer num = new Integer(10);
Integer num2 = new Integer(10);
int i = 10;
System.out.println("래퍼클래스 == 기본타입 : "+(num == i));
System.out.println("래퍼클래스.equals(기본타입) : "+num.equals(i));
System.out.println("래퍼클래스 == 래퍼클래스 : "+(num == num2));
System.out.println("래퍼클래스.equals(래퍼클래스) : "+num.equals(num2));
wrapper class
의 비교연산은 AutoUnBoxing
에 가능하다.
- 인스턴스에 저장된 값에 대한 동등 여부 판단은
동등 연산자 ==
으로 불가능하다. -> wrapper class
객체의 주소값을 비교한다.
equals() 메소드
를 통해 가능하다.
Wrapping의 장점
- 기본 자료형을 클래스화 하여 클래스의 장점을 활용할 수 있게 된다.
System.out.println(Character.isDigit('A') ? "숫자다" : "숫자가 아니다");
System.out.println(Character.isDigit('2') ? "숫자다" : "숫자가 아니다");
System.out.println(Character.isDigit(65) ? "숫자다" : "숫자가 아니다");
System.out.println(Character.isDigit('가') ? "숫자다" : "숫자가 아니다");
System.out.println(Character.isDigit(44032) ? "숫자다" : "숫자가 아니다");
System.out.println("[isLetter 메소드]");
System.out.println(Character.isLetter('가'));
System.out.println(Character.isLetter('A'));
System.out.println(Character.isLetter('a'));
System.out.println(Character.isLetter('家'));
System.out.println(Character.isLetter('9'));
System.out.println(Character.isLetter('@'));
System.out.println(Character.isWhitespace('가'));
System.out.println((int) ' ');
System.out.println(Character.isWhitespace(32));
System.out.println(Character.isWhitespace(' '));
System.out.println(Character.toUpperCase('A'));
System.out.println(Character.toUpperCase('a'));
System.out.println(Character.toLowerCase('A'));
System.out.println(Character.toLowerCase('a'));
System.out.println(Character.toUpperCase('가'));
System.out.println(Character.toLowerCase('가'));
System.out.println(Character.toUpperCase('9'));
System.out.println(Boolean.parseBoolean(boolString));
System.out.println(Boolean.parseBoolean(boolString) && false);
System.out.println(Boolean.valueOf(boolString) && false);
일급 컬랙션
- 콜렉션을 wrapping 할 때, 그 외의 다른 멤버 변수가 없는 상태를
일급 컬랙션
이라고 한다.
- 다시 말해,
Collection
들을 한번 Wrapping 한 컬렉션이다.
예시
public class Car {
private int position;
public void move(MovingStrategy movingStrategy) {
if (movingStrategy.isMove()) {
position++;
}
}
public int getPosition() {
return position;
}
}
- Car라는 객체의 인스턴스를 3개 생성하는 경우
- 이 인스턴스들을 모두 함께 관리해야할 때, 일급 컬렉션인 Cars 클래스를 만들면 용이하다.
public Cars(List<Car> cars)
Car aCar = new Car()
Car bCar = new Car()
Car cCar = new Car()
public class Cars {
private List<Car> cars;
public Cars(List<Car> cars) {
this.cars = this.cars;
}
public List<Car> getCars() {
return cars;
}
}
콜렉션을 wrapping 할 때 가지는 이점
1. 하나의 인스턴스에서 비지니스 로직을 관리할 수 있다.
일급 컬랙션을 사용하지 않을 경우
- 자동차의 현재 위치가 3보다 큰 자동차를 가져오려 할 경우,
- 일급 컬렉션 Cars가 없다면 하나씩 가져오거나, List로 묶어서 처리해야한다.
- 중간에 빼먹는 실수를 할 수 있고, 비지니스 로직도 외부에서 관리하게 된다.
@Test
public void _3보다_큰_자동차가져오기() {
Car aCar = new Car();
Car bCar = new Car();
Car cCar = new Car();
List<Car> cars = new ArrayList<>();
cars.add(aCar);
cars.add(bCar);
cars.add(cCar);
cars.stream()
.filter(car -> car.getPosition() > 3)
.forEach(System.out::println);
}
일급 컬랙션을 사용할 경우
public List<Car> getCarsOverPosition(int position)
메소드를 정의하여 비지니스 로직을 내부에서(Cars 도메인에서) 관리할 수 있게 된다.
- 다시 말해, 비지니스에 종속적인 자료구조를 만들 수 있게 된다.
public class Cars {
private List<Car> cars;
public Cars(List<Car> cars) {
this.cars = cars;
}
public List<Car> getCars() {
return cars;
}
public List<Car> getCarsOverPosition(int position) {
return cars.stream()
.filter(car -> car.getPosition() > position)
.collect(Collectors.toList());
}
}
- Collection의 불변성 보장
- 상태와 행위를 한 곳에서 관리
- 이름이 있는 컬랙션