JAVA 제네릭(Generics)
JDK 1.5 버전에 처음 도입되었으며, 클래스 내부에서 사용한 데이터 타입을 외부에서 지정하는 기법을 의미한다.
타양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입체크를 한다.
제네릭은 크게 2가지의 장점을 가지고 있다.
-
타입의 안전성 : 의도하지 않은 타입의 객체가 저장되는 것을 막고, 다른 타입의 객체로 인한 타입 형태가 맞지 않아 발생하는 문제를 없애준다.
-
불필요한 형변환을 줄여 코드의 간결함 : 타입을 미리 명시함으로써 다른 타입의 객체가 저장되지 않아 객체를 꺼내 사용할 시 형변환을 통한 타입을 맞출 필요가 없어 코드를 간결하게 줄일 수 있다.
1. 제네릭 타입
- 대표적으로 많이 사용되는 클래스는 ArrayList가 있다.
- 타입을 파라미터로 가지는 클래스와 인터페이스, 선언시 클래스 또는 인터페이스 이름 뒤에 "<>"부호가 붙는다.
public class 클래스명<T> { ... }
public interface 인터페이스명<T> { ... }
2. 멀티 타입 파라미터
- 두 개 이상의 타입 파라미터를 사용해서 선언할 수 있다.
- 중복된 타입 파라미터를 생략한 다이아몬드(<>) 연산자는 자바 7부터 지원.
public class 클래스명<K,V> { ... }
public interface<K,V...> { ... }
Product<String,Integer> product = new Produce<String,Integer>();
3. 제네릭 메소드
- 매개변수 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드를 말한다.
- 리턴 타입 앞에 "<>" 기호를 추가하고 타입 파라미터를 기술한다.
- 타입 파라미터를 리턴타입과 매개변수에 사용한다.
public <타입 파라미터, ...> 리턴 타입 메소드명(매개변수, ...) { ... }
package GenericMethodExample;
public class Box<T> {
private T t;
public T getT() { return t; }
public void setT( T t ) { this.t = t; }
}
===============================================================
package GenericMethodExample;
public class Utill {
public static <T> Box<T> boxing(T t) {
Box<T> box = new Box<T>();
box.setT(t);
return box;
}
}
===============================================================
package GenericMethodExample;
public class Main {
public static void main(Stirng[] args) {
Box<Integer> box1 = Util.<Integer>boxing(100);
int intValue = box1.getT();
Box<String> box2 = Util.boxing("암묵적호출");
String stringValue = box2.getT();
}
}
- Util.<Intger>boxing(100); // 구체적 타입을 명시하는 호출 방법
- Util.boxing("암묵적호출"); // 암묵적 호출 방법
4. 제한된 타입 파라미터
- 타입 파라미터에 지정되는 구체적인 타입을 제한할 필요가 있을 경우 사용.
- 상속 및 구현 관계를 이용해서 타입을 제한한다.
public <T extends 상위타입> 리턴타입 메소드(매개변수, ...) { ... }
- 상위 타입은 클래스 뿐만 아니라 인터페이스도 가능하다. 인터페이스라고 해서 extends 대신 implements를 사용하지 않는다.
- 메소드의 중괄호 {} 안에서 타입 파라미터 변수로 사용 가능한 것은 상위 타입의 멤버(필드,메소드)로 제한된다.
- 하위 타입에만 있는 필드와 메소드는 사용할 수 없다.
public <T extends Number> int compare(T t1, T t2) {
double v1 = t1.doubleValue();
double v2 = t2.doubleValue();
return Double.compare(v1, v2);
}
- doubleValue() 메서드는 Number 추상클래스에서 기본으로 제공되는 메서드 이다.
5. 와일드카드 타입
- 제네릭 타입을 매개변수나 리턴타입으로 사용할 때 타입 파라미터를 제한할 목적으로 사용.
- 제네릭으로 구현된 메소드의 경우에는 선언된 타입으로만 매개변수를 입력해야 한다. 이를 상속받은 클래스, 혹은 부모 클래스를 매개변수로 사용하고 싶어도 불가능하며, 혹은 그 어떤 타입이 와도 상관 없는 경우에 대응하기 좋지 않다. 이를 위한 해법으로 와일드카드를 사용한다.
- Unbound WildCard (제한없음)
- 제네릭 타입 <?> 와 같은 형태로 물음표만 가지고 정의 되어진다. 내부적으로는 Object로 정의 되어서 모든 타입을 인자로 받을 수 있다. - Upper Bounded WildCard (상위 클래스 제한)
- 제네릭타입<? extends 상위타입> 와 같은 형태로 사용되고, 특정 클래스의 자식 클래스만을 인자로 받겠다는 선언이다. 주로 변수의 제한을 완화하게 하기 위해서 사용된다. - Lower Bounded WildCard (하위 클래스 제한)
- 제네릭타입<? super 하위타입> 와 같은 형태로 사용되고, Upper bounded 와는 반대로 특정 클래스의 부모 클래스만을 인자로 받겠다는 선언이다. 즉 하위 타입이 해당 자리에 들어갈 수 있는 가장 하위 타입이다.
6. 제네릭 타입의 상속과 구현
- 제네릭 타입을 부모 클래스로 사용 할 경우, 타입 파라미터는 자식클래스에도 기술해야 한다.
public class ChildProduct<T,M> extends Product<T,M> { ... }
- 추가적인 타입 파라미터를 가질 수 있다.
public class ChildProduct<T,M,C> extends Product<T,M> { ... }
- 제네릭 인터페이스를 구현할 경우, 타입 파라미터는 구현 클래스에도 기술해야 한다.
public class StorageImpl<T> implements Storage<T> { ... }
※ 참고. 제네릭 사용 시 자주 사용 되는 타입 인자
타입 인자 | 의미 |
E | Element |
K | Key |
N | Number |
T | Type |
V | Value |
R | Result |
'Java' 카테고리의 다른 글
[Java] CPU 점유율이 높은 스레드 상태 분석(Thread dump) (0) | 2020.11.10 |
---|---|
[Java] Lombok (0) | 2020.10.20 |
[Java] PriorityBlockingQueue (0) | 2020.10.05 |
[Java] Heap Memory Dump Analysis (0) | 2020.09.26 |
[Java] StringTokenizer (0) | 2020.09.13 |