제네릭이란?
상속관계에 대한 타입 안정성을 지키고 유연하게 타입을 확장할 수 있도록 도와주는 기능이다.
1
2
3
4
5
6
7
public class MyCustomList<T> {
public void addElement(T element) {
list.add(element);
}
}
위와 같이 제네릭 타입을 매개변수로 받는 메서드를 만들면 어떤 타입이 와도 관계없이 메서드를 사용할 수 있다.
이때, 제네릭을 선언한 클래스에서 모든 메서드나 변수의 타입을 처럼 특정 타입으로 맞춰주어야한다.
또한 제네릭 키워드 <> 안에는 대문자가 들어와야한다.
공변성 (Covariance)
공변성은 특정 객체의 타입이 다른 객체의 타입보다 더 구체적일 때, 이를 허용하는 속성이다.
List<? extends T>
와 같은 방식으로 공변성을 나타낼 수 있다.
이는 T 타입
또는 T의 하위 타입
의 객체들만을 담을 수 있는 List를 의미한다.
Repository
, Reposiory
를 extends
하는 하위 ?
들을 허용한다.
1
2
3
4
5
6
7
8
9
10
public class Covariance {
public static void main(String[] args) {
List<? extends Repository> covarianceRepositories = new ArrayList<>();
// covarianceRepositories.add(new Repository()); 컴파일 에러
// covarianceRepositories.add(new UserRepository()); 컴파일 에러
// covarianceRepositories.add(new PostRepository()); 컴파일 에러
}
}
List<? extends Repository>
는 Repository의
모든 하위 타입을 포함할 수 있으므로, 컴파일러는 이 리스트가 UserRepository만을 담는 리스트인지, PostRepository만을 담는 리스트인지, 아니면 둘 다를 담을 수 있는 리스트인지 알 수 없다.
따라서, 타입 안전성을 위배하지 않도록, 이러한 리스트에는 새로운 요소를 추가할 수 없다.
반공변성 (Contravariance)
반공변성은 특정 객체의 타입이 제네릭으로 명시된 타입보다 더 상위계층일 때, 이를 허용하는 속성이다.
List<? super T>
와 같은 방식으로 반공변성을 나타낼 수 있다.
이는 T 타입
또는 T의 상위 타입
의 객체들을 담을 수 있는 List를 의미한다.
Repository
, Reposiory
가 super로 취급
하는 상위 ?
들을 허용한다.
1
2
3
4
5
6
7
8
9
public class Contravariance {
public static void main(String[] args) {
List<? super Repository> contravariantList = new ArrayList<>();
contravariantList.add(new Repository());
contravariantList.add(new UserRepository());
contravariantList.add(new PostRepository());
}
}
List<? super Repository>
는 Repository
또는 그 상위 타입의 객체
들만을 담을 수 있다.
Repository는 UserRepository와 PostRepository의 상위 타입이기 때문에 리스트가 어떤 타입의 객체들을 받을 수 있는지 명확하므로
타입 안전성을 유지할 수 있어 컴파일 에러가 발생하지 않는다.
불공변성 (Contravariance)
불변성은 특정 객체의 타입이 정확히 일치할 때만 해당 타입의 객체들을 담을 수 있게 하는 속성이다.
제네릭에서는 기본적으로 불변성이 적용된다.
이는, List
T에 해당하는 타입들만
허용한다. (제네릭의 기본 값이다.)
1
2
3
4
5
6
7
8
9
public class Invariance {
public static void main(String[] args) {
List<Repository> invariantList = new ArrayList<>();
invariantList.add(new Repository());
invariantList.add(new UserRepository());
invariantList.add(new PostRepository());
}
}