✅ https://github.com/whiteship/live-study
👍목표
자바의 제네릭에 대해 학습하세요.
📖학습할 것 (필수)
📌 제네릭 사용법
📌 제네릭 주요 개념 (바운디드 타입, 와일드 카드)
📌 제네릭 메소드 만들기
📌 Erasure
💡 제네릭 사용법
제네릭은 자바5부터 추가되었으며 제네릭 타입을 이용함으로써 다양한 이점을 얻을 수 있다.
- 컴파일 시 강한 타입 체크를 할 수 있다. 이로 인해 미리 타입을 강하게 체크해서 에러를 사전에 방지 할 수 있다.
- 타입 변환(casting)을 제거 할 수 있다.
- 타입 변환을 할 필요가 없어 프로그램 성능이 향상된다.
제네릭은 컬렉션, 람다식, 스트림, NIO 등에서 널리 사용되며 자바 API doc을 보면 제네릭 표현이 많이 쓰여있기 때문에
반드시 알아두어야 한다.
// 제네릭 예쩨
public class 클래스명<T> {
...
}
public interface 인터페이스명<T> {
...
}
제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말하며 클래스 또는 인터페이스 이름 뒤에 "<>" 부호
가 붙고, 꺽쇠 사이에 타입 파라미터가 위치한다.
public class Generic<T> {
private T t;
public T getT() {
return this.t;
}
public void setT(T t) {
this.t = t;
}
}
간단한 Generic을 이용한 예제 클래스를 작성하였다. T 타입 변수 t에 대한 getter와 setter를 갖는 클래스이며 해당 클래
스 객체의 타입 파라미터를 "Integer" 타입으로 한정하였다.
Integer 타입으로 한정한 10에 대한 코드는 제대로 동작하였지만 generic.setT(10L) 코드 즉, Long 타입을 사용하면 IDE
가 컴파일 타임에 타입 오류를 출력하는것을 볼 수 있다.
인프런의 김영한 지식공유자님의 말에 따르면 가장 좋은 오류는 컴파일 타임에 발생하는 오류라 하였다..
💡 제네릭 주요 개념 (바운디드 타입, 와일드 카드)
바운디드 타입
타입 파라미터에 지정되는 구체 타입을 제한할 필요가 있을 때가 있을 때 사용하는 것이 바운디드 타입 파라미터이다.
제한된 타입 파라미터를 선언하려면 타입 파라미터 뒤에 extends 키워드를 붙이고 상위 타입을 명시하면 된다. 상위 타
입은 클래스 뿐만 아니라 인터페이스도 가능하며 인터페이스라고 해서 implements 키워드를 사용해야 하는 것은 아니
다.
public <T extends 상위 타입> 반환 타입 메서드(매개 변수, ...) {
...
}
public class Main {
public static void main(String[] args) {
int compareResult = compareInteger(10, 20);
System.out.println("compareInteger(10, 20) = " + compareResult);
compareResult = compareInteger(20, 10);
System.out.println("compareInteger(20, 20) = " + compareResult);
compareResult = compareInteger(20.3, 20.2);
System.out.println("compareInteger(20.3, 20.2) = " + compareResult);
}
public static <T extends Number> int compareInteger(T t1, T t2) {
return Integer.compare(t1.intValue(), t2.intValue());
}
}
Output:
compareInteger(10, 20) = -1
compareInteger(20, 20) = 1
compareInteger(20, 20) = 0
위의 예제 코드는 숫자 타입만 구체 타입으로 갖는 제네릭 메서드 compareInteger에 대한 것으로 두 개의 정수 타입을
인자로 받아서 값을 비교한 결과를 int 타입으로 반환한다.
세번째 비교인 compareResult = compareInteger(20.3, 20.2);
System.out.println("compareInteger(20.3, 20.2) = " + compareResult);
의 출력 결과가 0인 것은 20.3과 20.2를 정수인 20으로 비교하였기 때문이다.
와일드 카드
자바의 와일드 카드에는 ?가 있으며 제네릭 타입을 매개 값이나 반환 타입으로 사용할 때 구체 타입 대신 와일드 카드(?)
를 사용할 수 있다.
- 제네릭 타입<?> : Unbounded Wildcards(제한 x)
- 타입 파라미터를 대치하는 구체 타입으로 모든 클래스나 인터페이스 타입이 올 수 있음
- 제네릭타입<? extends 상위 타입>: Upper Bounded Wildcards(상위 클래스 제한)
- 타입 파라미터를 대치하는 구체적인 타입으로 상위 타입이나 하위 타입만 올 수 있음
- 제네릭타입<? super 하위 타입>: Lower Bounded Wildcards(하위 클래스 제한)
- 타입 파라미터를 대치하는 구체 타입으로 하위 ㅌ입이나 상위 타입이 올 수 있음
💡 제네릭 메소드 만들기
제네릭 메서드는 파라미터 타입과 반환 타입으로 타입 파라미터를 갖는 메서드를 말한다. 제네릭 메서드를 선언하는 방
법은 반환 타입 앞에 <> 기호를 추가하고 타입 파라미터를 기술한 다음, 반환 타입과 파라미터 타입으로 타입 파라미터
를 사용하면 된다.
public <타입파라미터,...> 반환타입 메서드명(매개변수...) {
...
}
public <T> Generic<T> genericMethod(T t) {
...
}
제네릭 메서드를 호출하는 방법은 다음과 같다.
반환타입 변수 = <구체적 타입> 메서드명(매개값); // 1. 명시적으로 구체 타입 지정
반환타입 변수 = 메서드명(매개값); // 2. 매개값을 보고 구체적 타입을 추론
// ex)
Generic<Integer> generic = <Jnteger>genericMethod(10); // (1)
Generic<Integer> generic = genericMethod(10); // (2)
💡 Erasure
Erasure란 원소 타입을 컴파일 타임에만 검사하고 런타임에는 해당 타입 정보를 알 수 없는 것으로 컴파일 타임에만 타
입에 대한 제약 조건을 적용하고 런타임에는 타입 정보를 'Erasure'하는 것을 말한다.
자바의 Erasure는 제네릭 사용시 자바의 하위 버전과의 호환성을 지키기 위해 컴파일 타임에만 타입을 체크하고 런타임
에는 타입 체크를 하지 않는 것이다.
// 제네릭 사용 코드
public static <E> boolean containsElement(E [] elements, E element){
for (E e : elements){
if(e.equals(element)){
return true;
}
}
return false;
}
// 컴파일러는 unbound type E를 실제 타입의 Object로 변환한다.
public static boolean containsElement(Object [] elements, Object element){
for (Object e : elements){
if(e.equals(element)){
return true;
}
}
return false;
}
컴파일러는 type erasure를 통해 코드의 type safety을 보장하고 런타임 오류를 방지한다.
References
이것이 자바다(신용권 저)
jyami.tistory.com/99 (Erasure)
www.baeldung.com/java-type-erasure(Erasure 코드 예시)
TCP School
'스터디할래(Java 시리즈) > 스터디 과제' 카테고리의 다른 글
스터디할래 - 15주차 과제: 람다식 (0) | 2021.03.05 |
---|---|
스터디할래 - 13주차 과제: I/O (0) | 2021.02.20 |
스터디할래 - 12주차 과제: 애노테이션 (0) | 2021.02.19 |
스터디할래 - 11주차 과제: Enum (0) | 2021.02.16 |
스터디할래 - 10주차 과제: 멀티쓰레드 프로그래밍 (0) | 2021.01.22 |