🔖 INDEX
공변성 (Covariance)
공변성은 하위 타입 간의 관계를 유지하는 것을 의미합니다. 예를 들어, 클래스 A가 클래스 B를 상속하고 있을 때, List<A>와 List<B> 사이의 관계를 고려해봅시다. 공변성이 허용되는 경우, List<B>는 List<A>의 하위 타입으로 간주됩니다. 그러나 자바의 제너릭은 기본적으로 불변성을 따르므로, 이러한 관계가 자동으로 성립하지 않습니다. 자바에서 공변성을 처리하려면 와일드카드를 사용해야 합니다. 와일드카드를 사용하여 공변성을 지원하는 제너릭 타입을 선언할 수 있습니다.
List<? extends A> covariantList;
위 코드에서 List<? extends A>는 A와 A의 모든 하위 타입을 포함하는 리스트를 가리킵니다. 따라서 이 경우에는 List<B>를 List<? extends A>에 할당할 수 있습니다.
반공변성 (Contravariance)
반공변성은 상위 타입 간의 관계를 유지하는 것을 의미합니다. 예를 들어, 클래스 A가 클래스 B를 상속하고 있을 때, Consumer<A>와 Consumer<B> 사이의 관계를 고려해봅시다. 반공변성이 허용되는 경우, Consumer<A>는 Consumer<B>의 하위 타입으로 간주됩니다. 자바에서 반공변성을 처리하려면 와일드카드를 사용해야 합니다. 와일드카드를 사용하여 반공변성을 지원하는 제너릭 타입을 선언할 수 있습니다.
List<? super B> contravariantList;
위 코드에서 List<? super B>는 B와 B의 모든 상위 타입을 포함하는 리스트를 가리킵니다. 따라서 이 경우에는 List<A>를 List<? super B>에 할당할 수 있습니다.
이처럼 공변성과 반공변성의 사용은 매개변수화된 타입을 안전하게 사용할 수 있도록 돕습니다. 이 두 가지 개념은 특히 메소드의 매개변수 및 반환 타입에 대한 타입 제한을 지정할 때 유용합니다. 이를 통해 개발자들은 제너릭 코드를 더 유연하게 사용할 수 있으며, 이로 인해 실행 시간에 발생할 수 있는 타입 오류를 컴파일 시간에 방지할 수 있습니다.
공변성과 반공변성 사용 예제
아래 예제에서 공변성과 반공변성을 사용하여 메소드 매개변수 및 반환 타입에 대한 타입 제한을 지정하는 방법을 살펴보겠습니다.
import java.util.List;
import java.util.ArrayList;
class Animal {}
class Mammal extends Animal {}
class Dog extends Mammal {}
public class GenericsExample {
// 공변성을 사용하여 동물 리스트를 처리하는 메소드
// <? extends Animal>을 사용하여 Animal의 서브타입을 허용
public static void processAnimalList(List<? extends Animal> animalList) {
for (Animal animal : animalList) {
System.out.println(animal);
}
}
// 반공변성을 사용하여 동물 리스트에 동물을 추가하는 메소드
// <? super Mammal>을 사용하여 Mammal의 슈퍼타입을 허용
public static void addAnimalToList(List<? super Mammal> mammalList, Mammal mammal) {
mammalList.add(mammal);
}
public static void main(String[] args) {
List<Animal> animalList = new ArrayList<>();
List<Mammal> mammalList = new ArrayList<>();
List<Dog> dogList = new ArrayList<>();
// 공변성을 사용하여 다양한 동물 리스트를 처리
// processAnimalList는 Animal의 서브타입 리스트를 처리할 수 있음
processAnimalList(animalList);
processAnimalList(mammalList);
processAnimalList(dogList);
// 반공변성을 사용하여 동물 리스트에 동물을 추가
// addAnimalToList는 Mammal의 슈퍼타입 리스트에 Mammal 객체를 추가할 수 있음
addAnimalToList(animalList, new Mammal());
addAnimalToList(mammalList, new Mammal());
// 반공변성 때문에 컴파일 오류 발생
// dogList는 Mammal의 서브타입 리스트이기 때문에 Mammal 객체를 추가할 수 없음
// addAnimalToList(dogList, new Mammal()); // 컴파일 오류
}
}
위 예제에서 processAnimalList 메소드는 공변성을 사용하여 Animal의 하위 타입을 포함하는 리스트를 처리할 수 있습니다. 반면 addAnimalToList 메소드는 반공변성을 사용하여 Mammal의 상위 타입을 포함하는 리스트에 동물을 추가할 수 있습니다.
이러한 방식으로 공변성과 반공변성을 사용하면 제너릭 코드를 더 유연하고 안전하게 사용할 수 있습니다.
'프로그래밍 > JAVA' 카테고리의 다른 글
초보 자바 프로그래밍(38) - 문자열 변환 (0) | 2023.05.02 |
---|---|
초보 자바 프로그래밍(37) - 문자열과 String 클래스 (0) | 2023.05.02 |
초보 자바 프로그래밍(35) - 제너릭 (Generics) (0) | 2023.05.02 |
초보 자바 프로그래밍(34) - 배열과 ArrayList 비교 (0) | 2023.05.02 |
초보 자바 프로그래밍(33) - 가변 인자를 사용한 메서드 작성 (0) | 2023.05.02 |
댓글