'데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법'
ex) 어떤 자료구조를 만들어 배포하려 할때, String도 지원하고싶고, Integer도 싶고 그 외에도 많은 타입을 지원하고 싶을때, 클래스를 하나씩 다 만들어서 지원할 것인가? 그렇지 않다. 우리는 이때 제네릭을 사용하면 된다.
클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것
재사용 가능하고 형식이 안전한 코드를 생성할 수 있는 프로그래밍 개념
제네릭 타입을 사용함으로써 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 제거할 수 있다.
실행시 타입 에러가 나는것보다 컴파일 시에 에러를 사전에 방지하는 것이 좋다.
제네릭을 사용하면 데이터 구조에서 값을 검색할 때 타입 캐스팅이 필요하지 않으므로 프로그램 성능이 향상될 수 있습니다. 이는 코드가 예상 데이터 유형을 이미 알고 있고 런타임 시 변환을 수행할 필요가 없기 때문입니다.
static멤버에 제네릭 타입을 사용 할 수 없다.
=> 정적 멤버가 클래스의 인스턴스가 아니라 클래스 자체와 연결되어 있고 클래스에서 생성된 모든 개체에 대해 일관되게 작동해야 하기 때문입니다
=> 클래스나 메서드 인스턴스를 사용할 때 데이터 유형에 대한 유연성과 적응성을 제공하도록 설계
=> 이는 정적 요소에서 예상되는 일관된 동작과 충돌.
제네릭 타입 파라미터로 <T>, <E>, <K>, <N>, <V>, <R>
등이 주로 사용된다. type, element, key, number, value, result 를 많이 사용한다. 물론 써져 있는 것을 그대로 따를 필요는 없다. 다만, 통상적으로 이렇게 많이 사용한다는 것은 알고 가자.
public class ClassName <T, K> { ... }
public class Main {
public static void main(String[] args) {
ClassName<String, Integer> a = new ClassName<String, Integer>();
}
}
위 처럼 사용한다면 <T>
는 String
, <K>
는 Integer
일 것이다.
이때 주의해야할 점
타입 파라미터로 명시할 수 있는 것은 참조 타입(Reference Type)밖에 올 수 없다. 즉, int, double 같은 primitive type은 올 수 없다는 것이다.
Wrapper Type으로 쓰는 이유가 바로 위와 같은 이유다.
<?>
: 타입 파라미터를 대치하는 것으로 모든 클래스나 인터페이스타입이 올 수 있다.<?extends 상위타입>
: 상위타입 객체의 하위 클래스만 올 수 있다.<?super 하위타입>
: 하위타입 객체의 상위 클래스만 올 수 있다.