Вы когда-нибудь слышали о «ПЭКС»?

Если да, то вы бы погуглили и нашли…

«Производитель Eрасширяет, Cпотребитель Sвыше».

А? Что такое производитель и потребитель…? На самом деле, понять эту концепцию сразу непросто.

Итак, давайте визуализируем эту концепцию, чтобы нам было легче ее понять!

Когда вы читаете некоторые коды, написанные на Java, велика вероятность, что вы столкнулись с этими странными вещами.

<? super SomeType>

or

<? extends SomeType>

Очевидно, это связано с понятиями «Общие типы» и «Наследование». Хорошо, по крайней мере, мы знаем, что такое «супер» и «расширяет».

Таким образом, в основном <? super SomeType> является «неопределенным (пока)» типом, но этот неопределенный тип должен быть суперклассом класса «SomeType».

То же самое касается <? extends SomeType>. Это тип, который должен расширять класс SomeType (он должен быть дочерним классом класса SomeType).

Теперь давайте подумаем о концепции наследования классов на диаграмме Венна:

Класс млекопитающих расширяет класс животных (класс животных является надклассом класса млекопитающих).

Класс Cat/Dog расширяет класс Mammal (класс Mammal является суперклассом класса Cat/Dog).

Это не очень сложно, верно? :)

Затем давайте подумаем о «кружках» на приведенной выше диаграмме как о «коробке», имеющей физический объем.

Вы НЕ МОЖЕТЕ положить большую коробку в меньшую.

Вы можете ТОЛЬКО положить меньшую коробку в большую.

Когда вы говорите <? super SomeType>, вы хотите описать «коробку», которая имеет тот же размер или больше, что и коробка «SomeType».

Если вы говорите <? extends SomeType>, то вы хотите описать «коробку» того же размера или меньше, что и коробка «SomeType».

Теперь вы можете подумать: «Хорошо, хорошо. Я все понимаю, так что же такое PECS?»

Мы почти закончили! :) нам просто нужно знать, что такое «Производитель» и «Потребитель».

Примером «Производителя» является список, из которого мы только читаем.

Примером «Потребителя» является список, в который мы только записываем.

Просто имейте в виду следующее:

  • Мы «читаем» от «производителя» и берем этот материал в свою коробку.
  • Мы «записываем» нашу собственную коробку в «потребителя».

Итак, нам нужно прочитать (взять) что-то от «производителя» и положить это в нашу «коробку». Это означает, что любые коробки, взятые у производителя, НЕ должны быть больше, чем наша «коробка». Вот почему «Producer E расширяется».

"Расширение" означает меньшую рамку (меньший кружок на диаграмме Венна выше). Коробки производителя должны быть меньше нашей коробки, потому что мы возьмем эти коробки у производителя и положим их в свою коробку. Мы не можем поставить ничего больше нашей коробки!

Кроме того, нам нужно написать (поместить) нашу собственную «коробку» в «потребителя». Это означает, что коробки потребителя НЕ должны быть меньше нашей собственной коробки. Вот почему «Cпотребитель Sсупер».

"Супер" означает большую рамку (большой кружок на диаграмме Венна выше). Если мы хотим поместить наши собственные коробки в потребителя, коробки потребителя должны быть больше, чем наша коробка!

Давайте визуализируем это:

Также мы можем рассмотреть «Потребитель»:

Теперь мы можем легко понять этот пример:

public class Collections { 
  public static <T> void copy(List<? super T> dest, List<? extends T> src) {
      for (int i = 0; i < src.size(); i++) 
        dest.set(i, src.get(i)); 
  } 
}

В приведенном выше примере мы хотим прочитать (взять) что-то из src и записать (поместить) это в dest. Таким образом, src — это «Производитель», и его «ящики» должны быть меньше (точнее), чем какой-либо тип T.

И наоборот, dest является «Потребителем», и его «коробки» должны быть больше (более общего), чем некоторый тип T.

Если бы «коробки» src были больше, чем у dest, мы не смогли бы поместить эти большие коробки в меньшие коробки, которые есть у dest.

Здорово!! Теперь у нас есть понятие PECS, и должно быть намного яснее, что означает «PECS»:

«Производительпродюсер Eрасширяет(должно быть меньше), Cпотребитель Sуправляет (должно быть больше)».

Хотите поаплодировать этой статье? :) Спасибо!!