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

Как задать ограничения сверху для Generics

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

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

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

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

# Ограничения сверху для Generics (Upper Bounded Wildcards)

Ограничения сверху позволяют указать, что обобщённый тип должен быть подтипом определённого класса или интерфейса. Это один из самых важных механизмов для работы с иерархией типов в Java.

Синтаксис и концепция

Ограничение сверху задаётся с помощью ключевого слова extends:

// Для типовых параметров
public class Container<T extends Number> {
    // T может быть Number или любой его подкласс
}

// Для wildcards
public void process(List<? extends Number> numbers) {
    // Список может содержать Number или его подклассы
}

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

1. Ограничение типового параметра класса

public class Calculator<T extends Number> {
    private T value;
    
    public Calculator(T value) {
        this.value = value;
    }
    
    public double toDouble() {
        return value.doubleValue(); // можем вызвать методы Number
    }
    
    public T getValue() {
        return value;
    }
}

// Использование
Calculator<Integer> intCalc = new Calculator<>(42); // OK
Calculator<Double> doubleCalc = new Calculator<>(3.14); // OK
Calculator<String> stringCalc = new Calculator<>("test"); // ОШИБКА компиляции

2. Ограничение в методе

public class NumericProcessor {
    // Метод работает только с Numbers
    public <T extends Number> double processNumbers(List<T> numbers) {
        double sum = 0;
        for (T num : numbers) {
            sum += num.doubleValue();
        }
        return sum;
    }
}

// Использование
NumericProcessor processor = new NumericProcessor();
processor.processNumbers(Arrays.asList(1, 2, 3)); // int
processor.processNumbers(Arrays.asList(1.5, 2.5, 3.5)); // double

3. Wildcards с ограничением сверху

public void printNumbers(List<? extends Number> numbers) {
    for (Number num : numbers) {
        System.out.println(num);
    }
    // numbers.add(5); // ОШИБКА! Нельзя добавлять
}

// Этот метод может принять List<Integer>, List<Double> и т.д.
List<Integer> integers = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.5, 2.5);

printNumbers(integers); // OK
printNumbers(doubles);  // OK

Множественные ограничения

Можно задать несколько ограничений через &:

public interface Printable {
    void print();
}

public abstract class Document {
    public abstract String getContent();
}

// Тип T должен быть подтипом и Document, и Printable
public <T extends Document & Printable> void processDocument(T doc) {
    doc.print();
    System.out.println(doc.getContent());
}

Ковариантность и контравариантность

Ограничения сверху связаны с концепцией ковариантности:

// КОВАРИАНТНОСТЬ: ? extends Number
public void example1(List<? extends Number> list) {
    // Можем читать элементы как Number
    Number num = list.get(0); // OK
    
    // Но не можем добавлять (кроме null)
    // list.add(5); // ОШИБКА
}

// КОНТРАВАРИАНТНОСТЬ: ? super Integer
public void example2(List<? super Integer> list) {
    // Можем добавлять Integer
    list.add(42); // OK
    
    // Но не можем брать как Integer
    // Integer i = list.get(0); // ОШИБКА
}

Практический пример: Generic Repository

public abstract class BaseEntity {
    protected Long id;
}

public interface Repository<T extends BaseEntity> {
    void save(T entity);
    T findById(Long id);
    List<T> findAll();
}

public class UserRepository implements Repository<User> {
    // User должен быть подтипом BaseEntity
    @Override
    public void save(User user) {
        // сохранение
    }
}

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

  1. Ограничение типовых параметров — когда нужны методы конкретного класса
  2. Wildcards с extends — для методов, которые только читают данные
  3. Множественные ограничения — когда требуется соответствие нескольким типам
  4. PECS правило — Producer Extends, Consumer Super

Ограничения сверху делают код типобезопаснее и позволяют полнее использовать возможности иерархии типов Java.