스터디할래 - 14주차 과제: 제네릭

 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