[백기선님과 함께하는 Live-Study] 14주차 - 제너릭

JoonYoung Maeng·2021년 2월 26일
0
post-thumbnail

✔️ 목표

자바의 제네릭에 대해 학습하세요.

✔️ 학습할 것 (필수)

  • 제네릭 사용법
  • 제네릭 주요 개념 (바운디드 타입, 와일드 카드)
  • 제네릭 메소드 만들기
  • Erasure

💡 제너릭(Generic)

제네릭이란 자바에서 다양한 타입의 객체들을 다루는 메소드나 컬렉션 클래스에서 사용하는 것으로, 컴파일 과정에서 타입을 체크해주는 기능을 말한다. 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 안정성이 높아지고, 캐스팅이 용이하다는 장점을 가진다.


💡 제너릭 사용법

제네릭 타입은 타입 파라미터를 가지고, <>안에 타입 파라미터가 위치한다. 일반적으로 타입 파라미터는 알파벳 한 글자로 표현한다.

public class Person<T> {...}
public interface Person<T> {...}

T와 같이 구체적인 타입을 명시하지 않고 타입 파라미터로 선언해 놓은 후 객체 생성시에 타입을 구체화 해주면 타입 변환을 최소화 해줄 수 있다.

package com.livestudy.fourteenth;

public class Person <T> {
    private T name;
    private T gender;

    public Person(T name, T gender) {
        this.name = name;
        this.gender = gender;
    }

    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }

    public T getGender() {
        return gender;
    }

    public void setGender(T gender) {
        this.gender = gender;
    }
}

이를 String 타입과 Integer 타입으로 각각 타입 파리미터를 구체화 하여도 에러 메세지를 나타내지 않고 정상적으로 작동하는 것을 확인할 수 있다.

package com.livestudy.fourteenth;

public class GenericTest {
    public static void main(String[] args) {
				// String 타입으로 선언
        Person<String> person= new Person<>("zayson","male");

        System.out.println("이름 : "+person.getName());
        System.out.println("성별 : "+person.getGender());

				// Integer 타입으로 선언
        Person<Integer> intPerson = new Person<>(1,0);

        System.out.println("이름 : "+intPerson.getName());
        System.out.println("성별 : "+intPerson.getGender());
    }
}

제네릭의 타입 파라미터는 일반적으로 알파벳 한 글자로 작성하고 아래와 같은 의미를 갖는다.

  • <T> : Type
  • <E> : Element
  • <K> : Key
  • <N> : Number
  • <V> : Value
  • <R> : Result

# 💡 제네릭의 주요 개념 (바운디드 타입, 와일드 카드)

📌 제네릭 바운디드 타입

제네릭 바운디드 타입은 제네릭으로 사용되는 파라미터 타입을 제한할 수 있는 것을 말한다.

public class Person<T extends Number> {...}
public interface Person<T extends Number> {...}

만약 위와 같이 제너릭의 파라미터를 정의한 경우 Numbers의 하위 클래스가 아닌 클래스는 타입 파라미터로 적용되는 것이 불가능하다. 따라서, String 같은 타입으로 Person 객체를 선언하는 경우 컴파일 에러를 출력하는 결과를 확인할 수 있다.

image

제네릭 바운디드 타입이 사용되는 가장 흔한 예시는 Comparable 이다. Comparable 인터페이스를 구현하면 compareTo 메소드를 오버라이딩 해야하는데 여기서 Comparable의 타입 파라미터를 와 같이 타입을 제한한다면 compareTo 메소드를 비교할 때 제한된 타입끼리만 비교가 가능하게 된다.

📌 제네릭 와일드카드

제네릭 와일드카드도 제네릭 바운디드 타입과 마찬가지로 제네릭의 타입 파라미터를 제한하는 기능을 갖는다. 제네릭 와일드카드는 ?를 이용해 표현한다. ?의 뜻은 모든 타입의 객체를 제네릭의 파라미터 타입으로 사용할 수 있다는 뜻을 지닌다. 하지만 이렇게 ? 한개로만 표현한다면 제네릭의 T와 같은 의미를 가지기에 의미가 없어 보인다. 따라서, 와일드카드를 사용하는 경우는 <? extends T> 혹은 <? super T>으로 상위, 하위 타입으로의 변환이 가능하도록 제한하는 기능을 제공한다.

  • <? extends T> : 와일드카드의 상위타입을 제한하는 것으로 T의 하위 타입 클래스만 사용 가능

  • <? suepr T> : 와일드카드의 하위타입을 제한하는 것으로 T의 상위 타입 클래스만 사용 가능

  • <?> : 모든 타입이 가능한 것을 말한다.


💡 제네릭 메소드

파라미터 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드를 제네릭 메소드라한다. 리턴 타입 앞에 "<>"를 추가하고 타입 파라미터를 기술하여 사용한다.

public <타입 파라미터,...> 리턴타입 메소드명(파라미터,...)형식으로 메소드를 기술한다. 일반적으로 타입 파라미터를 컴파일 시에 추론이 가능하기 때문에 앞의 <타입 파라미터> 부분을 생략할 수 있다.

public T getName() {
    return name;
}
public T getGender() {
    return gender;
}

💡 Erasure

Erasure란 타입 파라미터를 컴파일 타임에만 검사하고, 런타임 시에는 해당 타입 정보를 알 수 없게 하는 것을 말한다.

  • unbounded Type(<?>, <T>) → Object
  • bound type() → Comprarable
  • 제네릭 타입을 사용할 수 있는 일반 클래스, 인터페이스, 메소드에만 Erasure 적용

📃 Reference

제네릭 : https://k39335.tistory.com/41

제네릭 사용법 : https://coding-factory.tistory.com/573

제네릭 와일드카드 : https://siyoon210.tistory.com/16

제네릭 바운디드 타입 : https://yaboong.github.io/java/2019/01/19/java-generics-1/

제네릭 Erasure : https://devlog-wjdrbs96.tistory.com/263#recentEntries

profile
백엔드 개발자 지망생입니다!

0개의 댓글