반응형
Generic 이란?
List, Map, Set 등을 선언할 때, List<String>, List<Integer> 와 같은 코드를 사용함
위와 같이 <> 안에 Data Type을 지정해 줌
이 때, <> 안에 특정 Data Type을 미리 지정하지 않고 개발자의 필요에 의해 지정할 수 있도록 하는것이 Generic
한마디로 Generic은 Data Type을 일반화(generalize) 한다는 의미
우리가 같은 List를 List<Integer>, List<String>과 같이 Data Type만 달리해서 사용할 수 있는것도 List에서 Generic 문법이 사용되기 때문
JDK 1.5 버전 이후로 사용 가능
Wrapper Class 란?
- List<Integer>같은 코드를 보면 왜 int가 아닌 Integer을 사용하는데, 이 때 Integer와 같은 것들을 Wrapper Class라 함
- Primitive Type(byte, short, char, int, long, float, double, boolean)과 달리
- Wrapper Class(Byte, Short, Character, Integer, Long, Float, Double, Boolean)는 Primitive Type을 감싼 Object(객체)
- Boxing : Primitive Type -> Wrapper Class
- Unboxing : Wrapper Class -> Primitive Type
- ex) Integer n = Integer.valueOf(10); // Boxing
Generic 사용 이유
- Generic 사용 이전의 코드로 예제를 만들어 봄
public class GenericTest {
public static void main(String[] args) {
FruitBox appleBox = new FruitBox();
appleBox.set(new Apple());
Apple apple = (Apple) appleBox.get();
System.out.println(apple); // Apple 출력
}
static class FruitBox {
private Object obj;
public void set(Object obj) { this.obj = obj; }
public Object get() { return obj; }
}
static class Apple {
@Override
public String toString() { return "Apple"; }
}
}
- 크게 문제가 없어보이지만 아래의 세가지 문제가 발생할 수 있음
- 꺼내는 상황에서 매번 형변환이 필요함
- FruitBox에 Apple을 넣는다해도 Object로 들어가기 때문에, 들어갈땐 괜찮지만 get할때는 형변환 필요
- 아래 코드를 사용할 수 있음
appleBox.set("Apple");
- appleBox에는 Apple Object만 넣기를 의도했지만 String도 Object이기 때문에 넣는 것이 가능함
- 나중에 꺼낼 때 형변환 과정에서 컴파일 에러 발생
- 아래 코드를 사용할 수 있음, 위 코드와 비슷하지만 꺼낼 때, 직접 print 찍는 방법
appleBox.set("Apple");
System.out.println(appleBox.get());
- 이렇게 출력해버리면 처음 코드와 같이 "Apple"이 출력됨
- 개발자의 의도와는 전혀 다르지만 에러도 발생하지 않고 실행결과까지 같음
Generic 사용 예제
- FruitBox 클래스 옆에 <T>를 붙여주고, 전에 Object가 있던 자리를 모두 T로 바꿔줌
- 또한 객체를 생성할 때 FruitBox<Apple> 이런 식으로 생성
- 이 때, T를 타입 매개변수, Apple을 타입 인자라고 부름
public class GenericTest {
public static void main(String[] args) {
FruitBox<Apple> appleBox = new FruitBox();
appleBox.set(new Apple());
Apple apple = appleBox.get();
System.out.println(apple);
}
static class FruitBox<T> {
private T obj;
public void set(T obj) { this.obj = obj; }
public T get() { return obj; }
}
static class Apple {
@Override
public String toString() { return "Apple"; }
}
}
- 이런 식으로 Generic을 사용했을 때의 장점으로는
- 꺼낼 때 형변환이 필요 없음 => appleBox에는 Apple만 들어갔기 때문에 뺄때는 Apple임을 바로 알 수 있음
- set 과정에서 아까처럼 String을 넣을 수도 없음 (에러 발생 시켜줌) => Apple만 들어가야 되기 때문
여러개의 타입 매개변수 사용 가능
public static void main(String[] args) {
Box<String, Integer> box1 = new Box<>();
box1.set("Apple", 25);
System.out.println(box1); // Apple & 25 출력
Box<Integer, String> box2 = new Box<>();
box2.set(25, "Apple");
System.out.println(box2); // 25 & Apple 출력
}
static class Box<T1, T2> {
private T1 t1;
private T2 t2;
public void set(T1 t1, T2 t2) {
this.t1 = t1;
this.t2 = t2;
}
@Override
public String toString() {
return t1 + " & " + t2;
}
}
Generic class의 타입 인자 제한
- class Box <T extends Number> 등과 같이 생성해서 타입 인자를 Number(int, double, long, ...)으로 제한 할 수 있음
- 이런 식으로 제한하면 intValue()와 같이 특정 타입에만 적용할 수 있는 메소드를 에러 없이 사용할 수 있게되는 등의 장점
Generic Method
- Class 뿐만 아니라 Method에도 Generic을 적용시킬 수 있음
- 차이점이 있다면 앞에 <T>를 한 번 더 붙여줌으로써, 이 메소드가 Generic Method임을 나타내 줘야함
public class GenericTest {
public static void main(String[] args) {
Box<String> stringBox = BoxFactory.makeBox("Sweet");
Box<Double> doubleBox = BoxFactory.makeBox(7.59);
System.out.println(stringBox.get());
System.out.println(doubleBox.get());
}
static class BoxFactory {
public static <T> Box<T> makeBox(T o) {
Box<T> box = new Box<>();
box.set(o);
return box;
}
}
static class Box<T> {
private T x;
public void set(T x) {
this.x = x;
}
public T get() {
return x;
}
}
}
반응형
'JAVA > 기본 문법' 카테고리의 다른 글
[JAVA] Object 클래스 (1) | 2022.10.04 |
---|---|
[JAVA] Calendar 클래스 (0) | 2022.10.03 |
[JAVA] Big Integer (0) | 2022.10.03 |
[JAVA] String Builder, String Buffer (1) | 2022.10.03 |
[JAVA] 추상 클래스(Abstract Class)와 인터페이스(interface), 인터페이스의 default method (0) | 2022.10.03 |