[Java] 왜 제네릭을 사용해야 하는가?
왜 제네릭을 사용해야 하는가?
제네릭이란(Generic)이란
- 타입을 파라미터화해서 컴파일시 구체적인 타입이 결정되도록 하는 것
- 자바 5부터 추가된 기능.
- 컬렉션, 람다식(함수적 인터페이스), 스트링, NIO에서 널리 사용된다.
- 제네릭을 모르면 도큐먼트를 해석할 수 없다.
예제 1-1
Class ArrayList<E>
default BiConsumer<T,U> andThen(BiConsumer<? super T,? super I> after)
제네릭을 사용하므로서 얻는 이점
- 컴파일시 강한 타입 체크를 할 수 있다.
- 실행 시 타입 에러가 나는 것보다, 컴파일시 미리 타입을 강하게 체크해 에러를 사전에 방지.
- 타입 변환을 제거할 수 있다.
- 타입 변환이 많을수록 전체 애플리케이션 성능이 떨어진다.
예제 1-2
List list = new ArrayList();
list.add("hello");
String str = (String) list.get(0);
- 위의 코드에서는 강제 타입 변환이 두번 일어난다.
- 아래는 제네릭 적용 후 코드의 변화된 결과다.
예제 1-3
List<**String**> list = new ArrayList<**String**>();
list.add("hello");
String str = list.get(0);
- 타입 인자로 < String >을 선언하여 Down Casting을 수행하지 않게된다.
- Down Casting을 수행하는 것은 JVM의 간섭을 없애기에 좋지 않다.
다중 매개변수 기반 제네릭 클래스의 정의
- 다중 매개변수 기반 제네릭 클래스 정의도 가능하다.
- DBox<String, Integer> box = new DBox<String, Integer>();
타입 매개변수의 이름 규칙
일반적인 관례
- 한 문자로 이름을 짓는다.
- 대문자로 이름을 짓는다.
보편적인 선택
- E - Element
- K - Key
- N - Number
- T - Type
- V - Value
기본 자료형에 대한 제한 그리고 래퍼 클래스
- 제네릭의 타입 인자로 기본 자료형이 올 수 없으므로, 컴파일 오류 발생
- 기본 자료형의 값이 전달되면 Auto Boxing, Auto UnBoxing을 수행 한다.
매개변수화 타입을 타입 인자로 전달
매개변수 타입에 매개변수화 타입을 넣는다.
- < String > - 타입 인자
- < T > - 타입 매개변수
- Box< T > - 매개변수화 타입
제네릭 클래스의 타입 인자 제한하기
- class Box< T extends Number > { ... }
- 인스턴스 생성 시 타입 인자로 Number 또는 이를 상속하는 클래스만 올 수 있음.
- T로 전달이 되는 인자는 Number Class를 상속 또는 Number Class의 Instance만 가능.
타입 인자 제한의 효과
중요한 부분
- 제한을 하는 이유가 무엇인가??
- 제한하는데 끝나는 것이 아닌, 부가적으로 Number Class에 있는 메소드를 호출하는 효과
- 제네릭 클래스를 정의할때 extends를 통해 제한을 하는 경우가 많다.
제네릭 클래스의 타입 인자를 인터페이스로 제한
- T로 전달되는 이름은 Eatable Interface를 직접적으로, 혹은 간접적으로 구현한 이름만 올 수 있다.
하나의 클래스 하나의 인터페이스에 대해 동시 제한
예제 1-1
class Box<T extends Number & Eatable> { ... } // Class, Interface 동시 제한
제네릭 메소드의 정의
- 클래스 전체를 제네릭으로 선언하는 것이 아닌, 하나의 메소드에 대해 제네릭 선언을 하겠다.
- 제네릭 클래스에서의 타입 인자 < T >는 인스턴스를 생성하는 순간 초기화가 되었다.
- 제네릭 메소드에서의 타입 인자 < T >는 메소드가 호출 되는 순간 초기화 된다.
- 타입 인자 T 에는 기본 자료형이 올 수 없다.
예제 1-1
// **제네릭 메소드**
class BoxFactory {
public static <**T**> Box<**T**> makeBox(**T** o){
Box<**T**> box = new Box<T>();
box.set(o);
return box;
}
}
// 제네릭 메소드의 T는 메소드 호출 시점에 결정한다.
Box< String > sBox = BoxFactory.< **String** >makeBox("Sweet");
Box< Double > sBox = BoxFactory.< **Double** >makeBox(7.59); // 오토 박싱
// 다음과 같이 타입 인자 생략 가능
Box< String > sBox = BoxFactory.makeBox("Sweet");
Box< Double > sBox = BoxFactory.makeBox(7.59); // 오토 박싱
여기서 집중할 부분은 static < T > 이 부분이다.
- 메소드에 < T > 이러한 표시를 하는 것은 제네릭 메소드임을 의미 하는 것이다.
- public <타입 파라미터 . . . > 리턴타입 메소드명 (매개변수, . . . ) { . . . }
제네릭 메소드의 제한된 타입 매개변수 선언
< T extends Number >
- T는 Number를 상속하거나, Number이어야 한다.
- 하나의 메소드만을 대상으로 제네릭 선언을 하기 위해 Class에서 내려온거라 생각하면 된다.
- 즉, 제네릭 메소드임을 말하기 위해 위 같이 선언을 한 것이다.
Author And Source
이 문제에 관하여([Java] 왜 제네릭을 사용해야 하는가?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ym1085/Chapter15저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)