Java - 제네릭(Generic)
- 제네릭(Generic)은 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법을 말한다.
1 | class Person<T>{ |
- 위와 같이 사용한다면 외부에서 생성한 객체의 타입을 <>에 정의함으로써 Person클래스의 info라는 필드의 타입이 정의되는 것이다.
- p1으로 객체를 생성한다면 info의 데이터 타입은 String이 되는 것이고,
- p2로 객체를 생성한다면 info의 데이터 타입은 StringBuilder이 되는 것이다.
<T>
의 위치에는 레퍼런스 형만 올 수 있고, 기본 데이터 타입((primitive type) => int, char 등..)은 제네릭으로 사용할 수 없다.(기본 데이터 타입은 객체가 아님)- 따라서, 기본 데이터 타입을 객체인 것처럼 만들 수 있는 객체를 제공하는 wrapper 클래스를 사용한다.
int -> Integer
,double -> Double
…와 같이 사용Integer id = new Integer(1);
와 같이 생성하여 생성자의 매개변수로 넘길 수 있다.p1.id.intValue()
와 같이 wrapper 클래스(Integer)의 메서드를 사용하여 wrapper 클래스가 담고 있는 원시 데이터 타입으로 반환 받을 수 있다.
제네릭의 생략
- 다음과 같은 경우 제네릭은 생략 가능하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Person<T, S>{
public T info;
public S id;
Person(T info, S id){
this.info = info;
this.id = id;
}
}
public class GenericDemo {
public static void main(String[] args) {
EmployeeInfo ei = new EmployeeInfo(1);
Integer id = 10;
Person p1 = new Person(ei, id);
}
} - 이 경우, 이미 ei와 id의 타입을 자바가 알고 있기 때문에 제네릭을 생략할 수 있다.
제네릭의 제한
<T extends Info>
와 같은 형태로 사용Info
클래스 또는 인터페이스를 상속받는 클래스의 데이터 타입인 경우로 제한한다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27abstract class Info{
public abstract int getLevel();
}
class EmployeeInfo extends Info{
public int rank;
EmployeeInfo(int rank){
this.rank = rank;
}
public int getLevel(){
return this.rank;
}
}
class Person<T extends Info>{
public T info;
Person(T info){
this.info = info;
}
}
public class GenericDemo {
public static void main(String[] args) {
Person<EmployeeInfo> p1 = new Person<EmployeeInfo>(new EmployeeInfo(1));
Person<String> p2 = new Person<String>("부장"); // 이 경우에는 에러
}
}
Person<EmployeeInfo> p1 = new Person<EmployeeInfo>(new EmployeeInfo(1));
와 같이Info
를 상속받는EmployeeInfo
타입인 경우에는 정상적으로 사용이 가능하지만Person<String> p2 = new Person<String>("부장");
와 같이String
타입인 경우 에러가 발생하게 된다.- 즉,
class Person<T extends Info>{
에서 T에는 Info 클래스 혹은 그 자식만이 올 수 있다. abstract class Info{
같은 경우 추상 클래스가 아니라 일반 클래스 혹인 인터페이스인 경우에도 동일하다.Info
가 인터페이스라고 해서T extends Info>
의 부분이 implements로 변한다거나 하지는 않는다.
제네릭의 장점
- 타입 안정성을 제공한다.(의도하지 않은 타입의 객체를 저장하는 것을 막고, 저장된 객체를 꺼내올 때 원래의 타입과 다른 타입으로 형변환하여 발생할 수 있는 오류를 줄인다.)
- 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해진다.
- 다룰 객체의 타입을 미리 명시함으로써 형변환을 하지 않아도 되도록 하는 것이다.
- 기존에는 다양한 종류의 타입을 다루는 메서드의 매개변수나 리턴 타입으로 Object타입의 참조 변수를 많이 사용했고, 그로 인해 형변환이 불가피했지만, 이젠 Object타입 대신 원하는 타입을 지정해주기만 하면 되는 것이다.
참조
https://devbox.tistory.com/entry/Java-%EC%A0%9C%EB%84%A4%EB%A6%AD
https://www.youtube.com/watch?v=YUinFIexEQ4