Generics:<Type>
。Generic을 통해컴파일 시점에서Data Type이 지정되지 않아도,런타임 시점에서 동적으로Data Type을 할당하는 기능
▶Java는Type 지정을 강제하지만,Generic을 통해 동적으로 할당 가능
▶ 서로 다른Class Type에도범용적으로 재사용 가능한 코드를 작성하기 위해 사용.
▶런타임 시점에서클래스 외부에서Data Type을 지정 시클래스 내부에서Generic을 통해 동적으로Data Type을 지정받음.
。Data Type에 의존하지 않으면서Class또는Interface를 구현할 수 있다.
▶자료형에 의존하지 않으므로 범용(generic)으로 활용가능.
。casting과boxing / unboxing에 따른 성능 저하를 방지할 수 있음.
。angle bracket(<>) 라는template활용
▶<>안에 아무런 문자가 들어가도 상관 없으나 관습적으로T를 사용
Generic은참조형 변수만 선언 가능
。NPE 방지와 동시에타입 추론시참조형만 참조 가능하고,원시형은 참조가 불가능하므로
런타임 시점에서Data Type을 강제하여타입 안정성( type safety )을 제공함으로써Type 별 캐스팅을 통해 발생할 수 있는 문제점을 제거
。Type이 일치하지않아 발생하는Data Type문제로부터 자유롭고 안전함 ex )List<Integer>
클래스<DataType> 참조변수 = new 클래스<>()가 가능한 이유?
。컴파일러에 의해참조변수의Data Type이참조되었기에생성자쪽에서Data Type을 지정하지 않아도,컴파일러에 의해타입추론을 통해Data Type이 자동으로 지정됨
▶ 반대 경우로클래스<> 참조변수 = new 클래스<T>()의 경우는참조변수의Data Type을컴파일러가 확인할 수 없으므로 성립되지 않는다.
Object 클래스를 통해범용성을 확보하지 않는 이유?
。Object 클래스는최상위 부모 클래스이므로, 모든Class가Upcasting할 수 있으므로,범용성이 확보되는 특징이 존재.
。하지만,타입 확정하지 않으므로, 요구되는클래스와 전혀 다른클래스 객체가 전달되어예외가 발생할 수 있음.
▶Generics를 통한<T>를 통해타입안정성을 확보할 수 있다.
Generic정의
。메서드 레벨/클래스 레벨에서Generic을 지정할 수 있음.
클래스에Generic정의하기
。클래스명 <T> {}으로 정의
。Generic을 통해런타임 시점에서<Type>을 지정하여타입 확정후 사용
ex )new 클래스<데이터타입>()에서Data Type을 확정하여타입안정성확보public class Stack<T> { T[] data = new T[5]; } public class Program { static void Main(string[] args) { // DataType 지정하여 타입안정성 확보 Stack<Integer> s1 = new Stack<Integer>(); // 정수형 설정. Stack<String> s2 = new Stack<String>(); // 문자열 설정. } }▶
Stack<Integer>를 통해타입 확정
메서드에Generic정의하기
。메서드에서Generic을 활용하는 경우반환 type앞에<T>를 지정해야함public static <T> ApiResult<T> of(String code, String message, T data){ return new ApiResult<>(code,message,data); }▶
<T>: 해당메서드에서Generic을 사용을 위해 명시하는 선언부
매개변수를 쉼표로 구분 시 여러개를 지정 가능
class 클래스이름 < 매개변수1, 매개변수2 , .... >
ex )JpaRepositoy 인터페이스가 존재class TwoGen<T,V> { T ob1; V ob2; public TwoGen(T ob1, V ob2) { this.ob1 = ob1; this.ob2 = ob2; } public T OB1 { get { return ob1; } } public V OB2 { get { return ob2; } } } internal class Program { static void Main(string[] args) { TwoGen<int, string> t1 = new TwoGen<int, string>(150,"hello"); Console.WriteLine(t1.OB1 + t1.OB2) ; } }
Generictype의 명명규칙
。place holder에서 정의하는 규칙
▶ 규칙을 지켜야컴파일이 되거나 하는건 아니지만 통일성을 위해 규칙을 따르는게 좋다.
。<E>: 요소 ( Element )
Collection에서 주로 사용
ex )ArrayList<E>
。<K>: Key
。<V>: Value
。<N>: Number
。<T>: Type
。<S>,<U>,<V>: 2 , 3 , 4번째에 선언된 Type.
。<?>:Type Wildcard
Type Wildcard :
<?>
。어떤 타입이든 올 수 있다는 의미의unknown type
▶Generic의placeholder에 지정.
。List<?>: 모든type의List를 의미.
▶List<?> list1 = new ArrayList<String>();와일드카드 종류
- Unbounded Wildcard (
<?>) :
。아무 타입이나 상관없이 사용 가능.
ex )List<?>
- 상한 제한 Wildcard (
<? extends T>) :
。T또는T의 전체하위 Class type만 허용
。읽기 전용으로 주로 활용
▶ 값을 읽을 수 있어도 구체적인 type을 모르므로 요소 추가는 불가능
ex )List<? extends Number> list = new ArrayList<Integer>();:
。Number의 하위Type인Number,Integer,Double,Float를 허용.
- 하한 제한 Wildcard (
<? super T>) :
。T또는T의 상위 type만 허용
。쓰기 위주로 주로 사용
▶ 요소 값 추가가 가능
ex )List<? super Integer> list = new ArrayList<Number>();:
。Integer의 상위Type인Integer,Number,Object를 허용Producer extends, Consumer super 법칙
。<? extends T>: 데이터 읽기용도로 활용
。<? super T>: 데이터 쓰기용도로 활용
ex )Comparator<? super T>는 비교용도로 활용하므로super사용