← Назад к вопросам

Что такое Wildcard в Java?

2.3 Middle🔥 111 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Wildcard в Java

Wildcard (подстановочный знак) в Java — это символ ?, используемый при работе с generics (обобщённые типы) для создания гибких типизированных конструкций. Wildcard позволяет работать с неизвестным типом параметра шаблона.

Основные типы wildcards

1. Unbounded Wildcard (?)

Представляет любой тип. Используется когда тип параметра не важен.

public class WildcardExample {
    // Метод принимает List любого типа
    public static void printList(List<?> list) {
        for (Object obj : list) {
            System.out.println(obj);
        }
    }
    
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("A", "B", "C");
        List<Integer> integers = Arrays.asList(1, 2, 3);
        
        printList(strings);   // Работает
        printList(integers);  // Работает
    }
}

2. Upper Bounded Wildcard (? extends Type)

Ограничивает wildcard сверху — тип должен быть Type или его подклассом. Это covariant подстановка.

public class UpperBoundedExample {
    static class Animal {}
    static class Dog extends Animal {}
    static class Cat extends Animal {}
    
    // Принимает List животных или их подклассов
    public static void processAnimals(List<? extends Animal> animals) {
        for (Animal animal : animals) {
            System.out.println(animal.getClass().getSimpleName());
        }
    }
    
    public static void main(String[] args) {
        List<Dog> dogs = Arrays.asList(new Dog(), new Dog());
        List<Cat> cats = Arrays.asList(new Cat(), new Cat());
        
        processAnimals(dogs);  // Работает
        processAnimals(cats);  // Работает
        
        // Но нельзя добавлять элементы:
        // dogs.add(new Dog()); // Компиляционная ошибка
    }
}

3. Lower Bounded Wildcard (? super Type)

Ограничивает wildcard снизу — тип должен быть Type или его суперклассом. Это contravariant подстановка.

public class LowerBoundedExample {
    static class Animal {}
    static class Dog extends Animal {}
    
    // Принимает List, которая может содержать Dog или его родителей
    public static void addDogs(List<? super Dog> list) {
        list.add(new Dog());
        list.add(new Dog());
    }
    
    public static void main(String[] args) {
        List<Dog> dogs = new ArrayList<>();
        List<Animal> animals = new ArrayList<>();
        
        addDogs(dogs);     // Работает
        addDogs(animals);  // Работает
    }
}

PECS правило (Producer Extends Consumer Super)

При выборе типа wildcard используй мнемонику PECS:

  • Producer Extends — если читаешь данные из коллекции, используй ? extends Type
  • Consumer Super — если пишешь данные в коллекцию, используй ? super Type
public class PECSExample {
    // Producer: читаем животных
    public static void readAnimals(List<? extends Animal> animals) {
        for (Animal animal : animals) {
            // Используем как Animal
        }
    }
    
    // Consumer: добавляем животных
    public static void writeAnimals(List<? super Dog> animals) {
        animals.add(new Dog());
    }
}

Практические примеры

public class PracticalExample {
    // Копирование элементов из одной коллекции в другую
    public static <T> void copy(
        List<? super T> destination,
        List<? extends T> source
    ) {
        for (T item : source) {
            destination.add(item);
        }
    }
    
    // Поиск максимума (читаем элементы)
    public static <T extends Comparable<? super T>> T findMax(
        List<? extends T> list
    ) {
        T max = list.get(0);
        for (T item : list) {
            if (item.compareTo(max) > 0) {
                max = item;
            }
        }
        return max;
    }
    
    public static void main(String[] args) {
        List<Integer> src = Arrays.asList(1, 2, 3);
        List<Number> dst = new ArrayList<>();
        
        copy(dst, src);
        System.out.println(dst); // [1, 2, 3]
    }
}

Когда использовать wildcards

Используй wildcards в:

  • Сигнатурах методов (параметры и возвращаемые значения)
  • Переменных на время жизни

Не используй wildcards для:

  • Параметров типов классов
  • Если нужна гибкость в чтении И записи одновременно

Важные ограничения

// Нельзя использовать wildcard в создании объектов
// List<?> list = new ArrayList<?>(); // Ошибка

// Нельзя использовать wildcard как тип параметра метода
// public void method(? param) {} // Ошибка

Заключение

Wildcards — мощный инструмент для работы с generics, позволяющий писать более гибкий и переиспользуемый код. Понимание PECS правила критично для правильного их применения.

Что такое Wildcard в Java? | PrepBro