제네릭 : Generic
제네릭이란 결정되지 않은 타입을 파라미터로 처리하고 실제 사용할 때 파라미터를 구체적인 타입으로 대체시키는 기능
제네릭을 이용한 클래스
public class Box <T> {
public T content;
}
는 T가 타입 파라미터임을 뜻하는 기호이다.
Box 클래스는 T를 content 필드의 타입으로 사용하였다.
Box 객체가 생성될 시점에 content 의 타입이 정해진다.
제네릭을 이용한 객체 생성
Box<String> box = new Box<String>();
box.content = "Hello";
String content = box.content;
System.out.println(content); // -> Hello
Box<Integer> box = new Box<Integer>();
box.content = 100;
int content = box.content;
System.out.println(content); // -> 100
위의 예시처럼 Box 필드인 content에 문자열을 저장하고 싶다면 타입 파라미터에 String
을 넣고, 정수를 저장하고 싶다면 Integer
를 넣으면 된다.
주의할 점
/인용
타입 파라미터를 대체하는 타입은 클래스 및 인터페이스이다. 타입을 정수형으로 주고 싶을 때 Box<int>
로 하지 않은 이유는 기본 타입은 타입 파라미터의 대체 타입이 될 수 없기 때문이다. Box<int>
로 해도 오류는 나지 않지만 내부적으로 Integer로 변환되는 과정을 거치기 때문에 효율적인 측면에서 바람직하지 않다.
생성자 호출 시 타입 생략
Box<String> box1 = new Box<>();
Box<Integer> box2 = new Box<>();
변수를 선언할 때와 동일한 타입으로 호출하고 싶다면 생성자 호출 시 생성자에는 타입을 생략하고 <>
만 붙일 수 있다.
제네릭 타입 : Generic Type
제네릭 타입은 결정되지 않은 타입을 파라미터로 가지는 클래스와 인터페이스를 말한다.
제네릭 타입 선언
선언부에 <>
가 붙고 그 사이에 타입 파라미터들이 위치한다.
public class 클래스명<A, B, ...> { ... }
public interface 인터페이스명<A, B, ...> { ... }
타입 파라미터는 일반적으로 대문자 알파벳 한 글자로 표현한다. 외부에서 제네릭 타입을 사용하려면 타입 파라미터에 구체적인 타입을 지정해야 하는데, 만약 지정하지 않으면 Object 타입이 암묵적으로 사용된다.
제네릭 메소드 : Generic Method
제네릭 메소도는 타입 파라미터를 가지고 있는 메소드를 말한다.
제네릭 메소드 선언
타입 파라미터가 메소드 선언부에 정의된다는 점에서 제네릭 타입과 차이가 있다. 리턴 타입 앞에 <>
를 추가하고 타입 파라미터를 정의한 뒤, 리턴 타입과 매개변수 타입에서 사용한다.
public <A, B, ...> 리턴타입 메소드명(매개변수, ...} { ... }
제네릭 메소드 사용 예시
- 선언
public <T> Box<T> boxing(T t) { ... }
- 호출
Box<Integer> box1 = boxing(100); // (1)
Box<String> box2 = boxing("Hello"); // (2)
(1)은 100
의 클래스 타입이 Integer
이므로 타입 파라미터 T는 Integer
로 대체되어 Box<Integer>
가 리턴된다.
(2)는 "Hello"
의 클래스 타입이 String
이므로 타입 파라미터 T는 String
으로 대체되어 Box<String>
이 리턴된다.
제한된 타입 파라미터 : Bounded Type Parameter
모든 타입으로 대체할 수 없고, 특정 타입과 자식 또는 구현 관계에 있는 타입만 대체할 수 있는 타입 파라미터를 제한된 타입 파라미터라고 한다.
제한된 타입 파라미터 사용
public <T extends 상위타입> 리턴타입 메소드(매개변수, ... ) { ... }
상위 타입을 클래스뿐만 아니라 인터페이스도 가능하다.
제한된 타입 파라미터 예시
public <T extends Number> boolean compare(T t1, T t2) {
double v1 = t1.doubleValue(); // Number의 doubleValue() 메소드
double v2 = t2.doubleValue(); // Number의 doubleValue() 메소드
return (v1 == v2);
}
타입 파라미터를 Number타입
으로 제한하면서 Object의 메소드뿐만 아니라 Number가 가지고 있는 메소드
도 사용할 수 있게 된다. 위 코드에서 doubleValue() 메소드는 double 타입 값을 리턴하는 Number의 메소드이다.
와일드카드 타입 파라미터 : Wildcard Type Parameter
제네릭 타입을 매개값이나 리턴 타입으로 사용할 때 타입 파라미터로 ?(와일드카드) 를 사용할 수 있다.
모든 타입
리턴타입 메소드명(제네릭타입<?> 변수( { ... }
어떤 타입이든 올 수 있다.
상위 클래스 제한
리턴타입 메소드명 (제네릭타입<? extends 제한타입> 변수) { ... }
제한 타입
이나 제한 타입의 하위 타입
만 올 수 있다.
하위 클래스 제한
리턴타입 메소드명 (제네릭타입<? super 제한타입> 변수) { ... }
제한 타입
이나 제한 타입의 상위 타입
만 올 수 있다.
추가 자료
https://mangkyu.tistory.com/241
제네릭의 등장 배경부터 시작해서 PECS 공식까지 제네릭과 와일드카드 타입에 대하여 자세하게 설명되어있다.
참고 자료
이것이 자바다 Chapter 13