♨학습내용
☞ 제네릭 사용법
☞ 제네릭 주요 개념 (바운디드 타입, 와일드 카드)
☞ 제네릭 메소드 만들기
☞ Erasure
- 제네릭 사용법
- 제네릭 이란?
- 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법이다.
- 제네릭은 중복 코드의 제거를 위해 자바 5부터 나왔다.
- 객체의 타입을 컴파일 시에 체크해 객체의 타입 안정성을 높이고 형변환의 번거로움이 줄어든다.
- 제네릭 장점
1. 타입 안정성을 제공한다.
2. 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해진다.
- 제네릭 사용법
- 제네릭 타입(class<T>, interface<T>)
- 타입을 파라미터로 가지는 클래스와 인터페이스이다.
- 클래스 or 인터페이스 뒤에 '<>' 부호가 붙고, 사이에 타입 파라미터가 위치한다.
- 일반적으로 타입 파라미터는 대문자 알파벳 한 글자로 표현한다.
- 타입의 매개변수의 이름은 아무거나 들어가도 상관없지만, 공식문서의 Name Convention을 따르는 게 좋습니다.
public class 클래스명<T> {
}
public interface 인터페이스명<T> {
}
- E : 주로 자바 Collection framework에 사용되는 Element
- K : map에서 매개변수로 사용되는 Key
- V : map에서 매개변수로 사용되는 Value
- N : 숫자를 나타내는 Number
- T : 일반적으로 사용하는 제네릭 Type
- S : 두번째로 사용하는 일반 제네릭 Type
- U : 세번째로 사용하는 일반 제네릭 Type
- V : 네번째로 사용하는 일반 제네릭 Type
- 멀티 타입 파라미터(class<K, V, ...>, interface<K, V, ...>)
- 제네릭 타입은 두 개 이상의 멀티 타입 파라미터를 가질 수 있다.
public class Product<T, M> {
private T kind;
private M model;
public T getKind() { return this.kind; }
public M getModel() { return this.model; }
public void setKind(T kind){ this.kind = kind; }
public void setModel(M model){ this.model = model;}
}
- 제네릭 주요 개념 (바운디드 타입, 와일드 카드)
- 바운디드 타입
- 바운디드 타입 매개변수는 특정 타입의 서브타입으로 제한하는 것을 말한다.
- 클래스, 인터페이스, 메소드를 제네릭으로 작성할 때, 타입 변수를 제한하기 위해서는 Bounded Type으로 선언해야한다.
- <T extends 상위타입> 으로 타입변수를 지정하여 상위타입의 하위클래스로만 제한할 수 있다.
public class Example {
public static void main(String[] args) {
// bounded 내의 타입이 아니여서 컴파일 오류 발생
// BoundedGeneric<String> boundedGeneric = new BoundedGeneric<String>();
BoundedGeneric<Integer> boundedGeneric = new BoundedGeneric<>();
boundedGeneric.setT(Integer.valueOf(10));
boundedGeneric.print();
}
}
class BoundedGeneric<T extends Number>{
T t;
public void print(){
System.out.println(t);
}
public void setT(T t){
this.t = t;
}
}
- 와일드 카드
- 제네릭에서 와일드 카드는 <?>로 나타내며 알 수 없는 유형을 나타낸다.
- 와일드 카드는 파라미터 변수, 필드, 지역변수의 타입 그리고 리턴 타입에도 사용될 수 있다.
- 그러나 와일드 카드는 제네릭 메소드 호출, 제네릭 클래스 인스턴스 생성 또는 수퍼 타입의 타입 인자로는 사용될 수 없다.
import java.util.Arrays;
import java.util.List;
public class Example {
public static double sum(List<? extends Number> numberlist){
double sum = 0.0;
for(Number n : numberlist){
sum+=n.doubleValue();
}
return sum;
}
public static void main(String[] args) {
List<Integer> integerList = Arrays.asList(3, 6, 9);
System.out.println("sum : "+sum(integerList)); // 18.0
List<Double> doubleList = Arrays.asList(3.3, 6.6, 9.9);
System.out.println("sum : "+sum(doubleList)); // 19.8
}
}
- 제네릭타입<?> : Unbounded Wildcards(제한없음)
- 타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스나 인터페이스 타입이 올 수 있다.
- 제네릭타입<? extends 상위타입> : Upper Bounded Wildcards(상위클래스 제한)
- 타입 파라미터를 대치하는 구체적인 타입으로 상위 타입이나 하위 타입만 올 수 있다.
- 제네릭타입 <? super 하위타입> : Lower Bounded Wildcards (하위클래스 제한)
- 타입 파라미터를 대치하는 구체적인 타입으로 하위 타입이나 상위 타입이 올 수 있다.
- 제네릭 메소드 만들기
- 클래스가 전부가 아닌 메서드 하나에 대해 제네릭으로 정의할 수 있다.
class BoxFactory {
public <T> Box<T> makeBox(T o) {
Box<T> box = new Box<T>();
box.set(o);
return box;
}
}
- 제네릭 클래스는 인스턴스 생성 시 타입 인자를 결정하지만
- 제네릭 메서드는 메서드 호출 시점에 결정한다.
Box<String> sBox = BoxFactory.<String>makeBox("Hello");
Box<Double> dBox = BoxFactory.<Double>makeBox(3.69);
- 다음과 같이 타입 인자 생략이 가능하다.
Box<String> sBox = BoxFactory.makeBox("Hello");
Box<Double> dBox = BoxFactory.makeBox(3.69);
- double의 경우 wrapper클래스 Double형으로 오토박싱이 진행된다.
- 제네릭 메서드는 메서드 호출 시 전달되는 인자의 자료형을 근거로 판단한다.
- Erasure
- 자바는 하위 호환성을 지키기 위해 타입 소거를 만들었다.
- 제네릭의 타입 소거는 원소 타입을 컴파일 시기에만 검사하고 런타임에는 해당 타입의 정보를 알 수 없다는 개념이다.
- 이러한 개념이 나온 이유는, 제네릭 개념을 도입한 이후로 이전 버전의 자바와의 하위 호환성때문이다.
- Non-Reifiable Type 런타임에 타입 정보의 유무에 따라 타입을 나누는 개념이다.
- Refiable type : 런타임에 타입에 대한 정보를 가지고 있다.
primitive, non - generic, unbounded wildcards (<?>) 등 이 있다. - Non - Reifiable type : 런타임에 타입에 대한 정보가 없다.
type erasure 가 진행되는 대부분의 generic parameterized type 이 있다.
'Study > Java_study' 카테고리의 다른 글
Java_study_15 (람다식) (0) | 2021.09.27 |
---|---|
Java_study_13 (I/O) (0) | 2021.09.20 |
Java_study_12 (애노테이션) (0) | 2021.09.14 |
Java_study_11 (Enum) (0) | 2021.09.07 |
Java_study_10 (멀티쓰레드 프로그래밍) (0) | 2021.08.30 |