Ответ
PECS (Producer Extends, Consumer Super) — это мнемоническое правило для безопасного использования подстановочных типов (wildcards) ? extends и ? super в Java Generics. Оно определяет, какую операцию (чтение или запись) можно безопасно выполнять с коллекцией.
1. Producer Extends (? extends T)
Используется, когда коллекция производит (отдает) элементы типа T. С такой коллекцией можно безопасно читать, но нельзя добавлять новые элементы (кроме null).
// Коллекция — производитель Number
List<? extends Number> numbers = Arrays.asList(1, 2.5, 3L);
// БЕЗОПАСНО: Чтение. Все элементы можно трактовать как Number.
Number first = numbers.get(0);
Double second = (Double) numbers.get(1); // После проверки
for (Number n : numbers) { /* ... */ }
// НЕБЕЗОПАСНО / ОШИБКА КОМПИЛЯЦИИ: Запись.
// numbers.add(10); // Нельзя добавить Integer
// numbers.add(3.14); // Нельзя добавить Double
// Компилятор не знает точный тип внутри List.
2. Consumer Super (? super T)
Используется, когда коллекция потребляет (принимает) элементы типа T. В такую коллекцию можно безопасно записывать объекты T (и его подтипы), но читать можно только как Object.
// Коллекция — потребитель Integer
List<? super Integer> integers = new ArrayList<Number>();
// БЕЗОПАСНО: Запись. Можно добавлять Integer и его подтипы.
integers.add(42);
integers.add(100);
// НЕБЕЗОПАСНО: Чтение с конкретным типом.
// Integer i = integers.get(0); // Ошибка компиляции
// Компилятор знает только, что это некий супертип Integer.
// БЕЗОПАСНО: Чтение как Object.
Object obj = integers.get(0);
Итог:
- Для чтения используй
? extends T(коллекция — производитель). - Для записи используй
? super T(коллекция — потребитель). Это правило критически важно для написания типобезопасных обобщенных методов, таких какCollections.copy().
Ответ 18+ 🔞
Давай разжую тебе эту тему, а то смотрю, глаза стекленеют, как у пьяного ежа в тумане. PECS, блядь. Не какая-то там штука для фитнеса, а правило, чтобы твои дженерики не выстрелили тебе в ногу в самый ответственный момент.
Представь, есть у тебя коробка. И в ней что-то лежит. PECS — это инструкция, как с этой коробкой можно ебаться, чтобы не обосраться.
1. Producer Extends (? extends T) — Коробка-ДАВАЙКА
Ситуация: коробка производит для тебя штуки типа T. Ты из неё ТОЛЬКО берешь. Как холодильник с пивом — открыл, взял, закрыл.
// Коробка, в которой намешано Number: Integer, Double, Long — хуй пойми что, но всё — Number.
List<? extends Number> numbers = Arrays.asList(1, 2.5, 3L);
// МОЖНО, сука, брать! Всё, что достанешь, будет хотя бы Number. Это безопасно.
Number first = numbers.get(0); // Взял — и не парься.
for (Number n : numbers) { /* делай с ним что хочешь */ }
// НЕЛЬЗЯ, блядь, класть! Абсолютно НИ-ХУ-Я!
// numbers.add(10); // Ошибка компиляции! А вдруг внутри List<Double>?
// numbers.add(3.14); // Та же хуйня! А вдруг внутри List<Integer>?
// Компилятор не ебёт, что у тебя в голове. Он видит "? extends" и говорит: "Чувак, я понятия не имею, какой точный тип внутри. Поэтому класть туда нихуя нельзя, кроме null. Иди нахуй со своим добавлением".
Короче, ? extends — это когда коробка говорит: «Бери, пожалуйста, но совать своё — иди нахуй». Только чтение.
2. Consumer Super (? super T) — Коробка-ПРИНИМАЙКА
Ситуация: коробка потребляет штуки типа T. Ты в неё ТОЛЬКО кладешь. Как почтовый ящик для писем — кидаешь и забываешь.
// Объявили коробку, которая принимает Integer и всё, что выше (Number, Object).
List<? super Integer> integers = new ArrayList<Number>();
// МОЖНО, ёпта, класть! Integer? Окей. Его наследника? Тоже окей.
integers.add(42); // Идеально.
integers.add(100); // Без проблем.
// НЕЛЬЗЯ, сука, нормально ЧИТАТЬ! Вернее, прочитать-то можно, но...
// Integer i = integers.get(0); // ОШИБКА! А вдруг там лежит Object или Number?
// Компилятор орёт: "Э, бошка думай! Я знаю только, что это '? super Integer'. Может, там Object лежит? Нахуй твое приведение типов!"
// МОЖНО читать, но только как полнейшую абстракцию — Object. На что похоже? На выигрыш в лотерею, который оказался фантиком.
Object obj = integers.get(0); // Да, вот так. Пиздецкая полезность, да?
Итог по ? super: коробка говорит: «Давай сюда свои Integer, я всё проглочу. Но что я отрыгну обратно — не обещаю, может, просто Object». В основном для записи.
Так нахуя это всё?
А нахуя, спрашиваешь? Чтобы писать методы, которые не ебут мозг тем, кто будет их использовать. Классический пример — Collections.copy(dest, src).
dest(куда копируем) должен ПРИНИМАТЬ элементы из src. Значит, ему? super T.src(откуда копируем) должен ОТДАВАТЬ элементы. Значит, ему? extends T.
Вот и весь PECS, ёпта. Producer EXTENDS, Consumer SUPER. Запомни эту хуйню, и компилятор перестанет материться на тебя красными буквами. А то ведь реально, как с той Муму: хотел как лучше, а получил ClassCastException на ровном месте.