자바의 제네릭에 대해 학습하세요.
제네릭이란 자바에서 다양한 타입의 객체들을 다루는 메소드나 컬렉션 클래스에서 사용하는 것으로, 컴파일 과정에서 타입을 체크해주는 기능을 말한다. 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 안정성이 높아지고, 캐스팅이 용이하다는 장점을 가진다.
제네릭 타입은 타입 파라미터를 가지고, <>안에 타입 파라미터가 위치한다. 일반적으로 타입 파라미터는 알파벳 한 글자로 표현한다.
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());
}
}
제네릭의 타입 파라미터는 일반적으로 알파벳 한 글자로 작성하고 아래와 같은 의미를 갖는다.
제네릭 바운디드 타입은 제네릭으로 사용되는 파라미터 타입을 제한할 수 있는 것을 말한다.
public class Person<T extends Number> {...}
public interface Person<T extends Number> {...}
만약 위와 같이 제너릭의 파라미터를 정의한 경우 Numbers의 하위 클래스가 아닌 클래스는 타입 파라미터로 적용되는 것이 불가능하다. 따라서, String 같은 타입으로 Person 객체를 선언하는 경우 컴파일 에러를 출력하는 결과를 확인할 수 있다.
제네릭 바운디드 타입이 사용되는 가장 흔한 예시는 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란 타입 파라미터를 컴파일 타임에만 검사하고, 런타임 시에는 해당 타입 정보를 알 수 없게 하는 것을 말한다.
제네릭 : 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