와일드카드 : 제네릭 타입에서 타입 매개변수의 값을 미리 지정하지 않고 사용할 수 있는 기능.
한정적 와일드카드는 이러한 와일드카드를 특정한 타입의 하위 타입으로 제한하는 방법 중 하나이다. 이를 통해 API의 유연성을 높일 수 있다.
import java.util.List;
class Animal {
// 동물 클래스
}
class Dog extends Animal {
// 개 클래스
}
class Cat extends Animal {
// 고양이 클래스
}
public class AnimalProcessor {
// 모든 동물의 리스트를 처리하는 메서드
public static void processAnimals(List<? extends Animal> animals) {
for (Animal animal : animals) {
// 동물 처리 로직
System.out.println(animal.getClass().getSimpleName() + " is being processed.");
}
}
public static void main(String[] args) {
List<Dog> dogs = List.of(new Dog(), new Dog());
List<Cat> cats = List.of(new Cat(), new Cat());
// processAnimals 메서드는 List<Dog>와 List<Cat>을 모두 처리할 수 있음
processAnimals(dogs); // 개 리스트 처리
processAnimals(cats); // 고양이 리스트 처리
}
}
한정적 와일드카드는 메서드 시그니처에서 사용되고 있습니다. 메서드 processAnimals의 파라미터 타입인
List<? extends Animal>에서 한정적 와일드카드가 사용되었다. 이것은 Animal 클래스를 상속하는 모든 클래스(Animal 클래스를 포함하여)의 리스트를 받을 수 있음을 의미합니다. 따라서 List<Dog>와 List<Cat> 모두 이 메서드의 인자로 사용될 수 있습니다.
PECS(Producer Extends, Consumer Super) : 제네릭 타입을 다룰 때 사용되는 원칙 중 하나.
- Producer Extends: 생산자(Producer) 역할을 하는 메서드에서는 와일드카드의 extends를 사용한다. 이는 해당 제네릭 타입을 "읽기 전용"으로 사용한다는 것을 의미한다. 즉, 데이터를 가져오는 역할을 한다.
- Consumer Super: 소비자(Consumer) 역할을 하는 메서드에서는 와일드카드의 super를 사용한다. 이는 해당 제네릭 타입을 "쓰기 전용"으로 사용한다는 것을 의미한다. 즉, 데이터를 추가하거나 변경하는 역할을 한다.
import java.util.ArrayList;
import java.util.List;
class Animal {
public void makeSound() {
System.out.println("Animal is making a sound.");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog is barking.");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Cat is meowing.");
}
}
public class Main {
public static void main(String[] args) {
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
List<Cat> cats = new ArrayList<>();
cats.add(new Cat());
cats.add(new Cat());
// Producer - extends
// List<Dog>를 처리하는 메서드에는 List<? extends Animal>을 사용
processAnimals(dogs);
// Consumer - super
// List<Animal>를 받아서 처리하는 메서드에는 List<? super Dog>를 사용
addDogToList(cats);
processAnimals(cats);
}
/**
* 동물 리스트를 처리하는 메서드.
*
* @param animals 처리할 동물 리스트
*/
public static void processAnimals(List<? extends Animal> animals) {
for (Animal animal : animals) {
animal.makeSound();
}
}
/**
* 개를 리스트에 추가하는 메서드.
*
* @param animals 개를 추가할 리스트
*/
public static void addDogToList(List<? super Dog> animals) {
animals.add(new Dog());
}
}
이 코드에서 processAnimals 메서드는 List<? extends Animal>을 인자로 받아서 동물 리스트를 처리한다. 이 경우 List<Dog>와 List<Cat> 모두 processAnimals 메서드의 인자로 사용될 수 있도록 한정적 와일드카드를 사용한다.
addDogToList 메서드는 List<? super Dog>를 인자로 받아서 개 객체를 리스트에 추가합니다. 이 경우 List<Animal>을 포함하여 Animal 클래스의 상위 클래스를 인자로 받을 수 있도록 한정적 와일드카드를 사용한다.
결론 : 조금 복잡하더라도 와일드카드 타입을 적용하면 API가 훨씬 유연해진다. 그러니 널리 쓰일 라이브러리를 작성한다면 반드시 와일드카드 타입을 적절히 사용해줘야 한다. PECS공식을 기억하자. 즉, 생산자(producer)는 extends를 소비자(consumer)는 super를 사용한다.
'이펙티브 자바' 카테고리의 다른 글
[이펙티브 자바] 아이템 33. 타입 안전 이종 컨테이너를 고려하라 (0) | 2024.04.03 |
---|---|
[이펙티브 자바] 아이템 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라 (0) | 2024.04.01 |
[이펙티브 자바] 아이템 30. 이왕이면 제네릭 메서드로 만들라 (0) | 2024.04.01 |
[이펙티브 자바] 아이템 29. 이왕이면 제네릭 타입으로 만들라 (0) | 2024.03.28 |
[이펙티브 자바] 아이템 28. 배열보다는 리스트를 사용하라 (0) | 2024.03.28 |