Вопросы собеседования с java generics (ответы)

Введение

Обобщённое программирование — это такой подход к описанию данных и
алгоритмов, который позволяет их использовать с различными типами
данных без изменения их описания. В Java, начиная с версии J2SE 5.0,
добавлены средства обобщённого программирования, синтаксически
основанные на C++. Ниже будут рассматриваться generics (дженерики) или <<контейнеры типа T>> — подмножество обобщённого программирования.

Допустим мы ничего не знаем о дженериках и нам необходимо реализовать специфический вывод на консоль информации об объектах различного типа (с использованием фигурных скобок).

Ниже пример реализации:

В вышеприведённом коде была допущена ошибка, из-за которой на консоли мы увидим следующее:

Теперь на время забудем об этом примере и попробуем реализовать тот же функционал с использованием дженериков (и повторим ту же ошибку):

Самое существенное отличие (для меня) в том, что при ошибке, аналогичной предыдущей, проблемный код не скомпилируется:

Думаю, многие согласятся, что ошибка компиляции «лучше» ошибки времени выполнения, т.к. чисто теоретически скомпилированный код с ошибкой может попасть туда, куда ему лучше бы и не попадать. Это очевидное достоинство дженериков. Теперь подробнее рассмотрим конструкции, относящиеся к дженерикам в этом примере. Для того, чтобы код скомпилировался, достаточно заменить строку

Посмотрим на декларацию BoxPrinter:

После имени класса в угловых скобках «<» и «>» указано имя типа «Т», которое может использоваться внутри класса. Фактически Т – это тип, который должен быть определён позже (при создании объекта класса).

Внутри класса первое использование T в объявлении поля:

Здесь объявляется переменная дженерик-типа (generic type), т.о. её тип будет указан позже, при создании объекта класса BoxPrinter.

В main()-методе происходит следующее объявление:

Здесь указывается, что Т имеет тип Integer. Грубо говоря, для объекта value1 все поля Т-типа его класса BoxPrinter становятся полями типа Integer (private Integer val;).
Ещё одно место, где используется T:

Как и в декларации val с типом Т, вы говорите, что аргумент для конструктора BoxPrinter имеет тип T. Позже в main()-методе, когда будет вызван конструктор в new, указывается, что Т имеет тип Integer:

Теперь, внутри конструктора BoxPrinter, arg и val должны быть одного типа, так как оба имеют тип T. Например следующее изменение конструктора:

приведёт к ошибке компиляции.

Последнее место использования Т в классе – метод getValue():

Тут вроде тоже всё ясно – этот метод для соответствующего объекта будет возвращать значение того типа, который будет задан при его (объекта) создании.

При создании дженерик-классов мы не ограничены одним лишь типом (Т) – их может быть несколько:

Нет ограничений и на количество переменных с использующих такой тип:

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

Дженерики в Java – это термин, обозначающий набор языковых возможностей, связанных с определением и использованием общих типов и методов. Общие методы Java отличаются от обычных типов данных и методов. До Generics мы использовали коллекцию для хранения любых типов объектов, т.е. неуниверсальных. Теперь Generics заставляет программиста Java хранить объекты определенного типа.

Если вы посмотрите на классы платформы Java-коллекции, то увидите, что большинство классов принимают параметр / аргумент типа Object. По сути, в этой форме они могут принимать любой тип Java в качестве аргумента и возвращать один и тот же объект или аргумент. Они в основном неоднородны, т.е. не похожего типа.

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

В традиционном подходе после получения ввода проверяется тип данных ввода, а затем назначается переменная правого типа данных. При использовании этой логики длина кода и время выполнения были увеличены. Чтобы избежать этого, были введены дженерики.

Когда вы используете Generics, параметры в коде автоматически проверяются во время компиляции, и он устанавливает тип данных по умолчанию. Так что это то место, где вам нужна концепция обобщений в Java.

Существует 4 различных способа применения:

  1. Типовой класс
  2. Интерфейс
  3. Метод
  4. Конструктор

Иерархия и классификация

Согласно спецификации языка Java :

  • Тип переменной является безусловным идентификатором. Переменные типа вводятся объявлениями универсального класса, объявлениями универсального интерфейса, объявлениями универсального метода и объявлениями универсального конструктора.
  • Класс является общим , если он объявляет одну или несколько переменных типа. Эти переменные типа известны как параметры типа класса. Он определяет одну или несколько переменных типа, которые действуют как параметры. Объявление универсального класса определяет набор параметризованных типов, по одному для каждого возможного вызова раздела параметров типа. Все эти параметризованные типы используют один и тот же класс во время выполнения.
  • Интерфейс является общим , если он объявляет одну или несколько переменных типа. Эти переменные типа известны как параметры типа интерфейса. Он определяет одну или несколько переменных типа, которые действуют как параметры. Объявление универсального интерфейса определяет набор типов, по одному для каждого возможного вызова раздела параметров типа. Все параметризованные типы используют один и тот же интерфейс во время выполнения.
  • Метод является общим , если он объявляет одну или несколько переменных типа. Эти переменные типа известны как параметры формального типа метода. Форма списка параметров формального типа идентична списку параметров типа класса или интерфейса.
  • Конструктор может быть объявлен как родовые, независимо от того , класса , что конструктор объявлен в сам родовом. Конструктор является универсальным, если он объявляет одну или несколько переменных типа. Эти переменные типа известны как параметры формального типа конструктора. Форма списка параметров формального типа идентична списку параметров типа универсального класса или интерфейса.

Интерфейс

Интерфейс в Java относится к абстрактным типам данных. Они позволяют манипулировать коллекциями Java независимо от деталей их представления.

Кроме того, они образуют иерархию в объектно-ориентированных языках программирования.

//Generic interface definition
interface GenericInterface<T1, T2>
{
T2 PerformExecution(T1 x);
T1 ReverseExecution(T2 x);
}

//A class implementing generic interface
class Genericclass implements GenericInterface<String, Integer>
{
public Integer PerformExecution(String x)
{
//execution code
}
public String ReverseExecution(Integer x)
{
//execution code
}
}

3 | Нехватка настойчивости при возникновении проблемы

Если вы легко сдаетесь при любой возникшей проблеме, вы никогда не станете успешным программистом.

Проблемы являются сущностью программирования. Только из-за них и были изобретены компьютеры! Когда вы начинаете работать над программой, вы сталкиваетесь с целой кучей проблем. И когда вы решаете одну, за ней практически всегда возникает новая. Вы продвигаетесь вперед, но всегда появляются новые проблемы.

Перспектива решения этой кучи проблем может быть пугающей и обескураживающей. Если вы считаете, что всё должно “просто работать”, тогда у вас не будет запала продолжать работать, когда проблемы продолжат возникать и потихоньку подтачивать вашу силу воли. И это и есть ваша работа: выяснить, почему программа не работает.

По моему опыту работы, в классе обычно есть 1–2 ученика, обладающих, похоже, удивительной способностью сталкиваться с большим количеством проблем, чем другие. Часто это просто случайные и скрытые проблемы. Я напоминаю студентам, что чем больше проблем встаёт перед ними, тем больше у них возможностей учиться. Если, решая эти проблемы, они понимают что-то новое, они будут чувствовать себя увереннее, так как решили больше проблем, чем “средний” студент.

Терпеливое принятие: Вам нужно понять, что проблемы — неотъемлемая часть работы. Да и вообще это не проблемы, а, скорее, вызовы. Каждый вызов, который вы принимаете и разрешаете, даёт вам более глубокое понимание, способность лучше воспринимать новые вызовы и справляться со старыми.

Универсальные методы (Generic methods)

По аналогии с универсальными классами (дженерик-классами), можно создавать универсальные методы (дженерик-методы), то есть методы, которые принимают общие типы параметров. Универсальные методы не надо путать с методами в дженерик-классе. Универсальные методы удобны, когда одна и та же функциональность должна применяться к различным типам. (Например, есть многочисленные общие методы в классе java.util.Collections.)

Рассмотрим реализацию такого метода:

Нам в первую очередь интересно это:

«<T>» размещено после ключевых слов «public» и «static», а затем следуют тип возвращаемого значения, имя метода и его параметры. Такое объявление отлично от объявления универсальных классов, где универсальный параметр указывается после имени класса. Тело метода вполне обычное – в цикле все элементы списка устанавливаются в одно значение (val). Ну и в main()-методе происходит вызов нашего универсального метода:

Стоит обратить внимание на то, что здесь не задан явно тип параметра. Для IntList – это Integer и 100 тоже упаковывается в Integer

Компилятор ставит в соответствие типу Т – Integer.

Возможны ошибки, связанные с импортом List из java.awt вместо java.util

Важно помнить, что список из java.util является универсальным типом а список из java.awt — нет

А сейчас вопрос – какая (-ие) из нижеприведённых строк откомпилируется без проблем?

Перед ответом на этот вопрос следует учесть, что List – интерфейс, ArrayList наследуется от List; Number — абстрактный класс и Integer наследуется от Number.

Ответ с пояснением:
Первый вариант неправильный, т.к. нельзя создавать объект интерфейса.
Во втором случае мы создаем объект типа ArrayList и ссылку на него базового для ArrayList класса. И там, и там дженерик-тип одинаковый – всё правильно.
В третьем и четвёртом случае будет иметь ошибка компиляции, т.к. дженерик-типы должны быть одинаковыми (связи наследования здесь никак не учитываются).

Условие одинаковости дженерик-типов может показаться не совсем логичным. В частности хотелось бы использовать конструкцию под номером 3. Почему же это не допускается?

Будем думать от обратного – допустим 3-ий вариант возможен. Рассмотрим такой код:

Первая строка кода смотрится вполне логично, т.к. ArrayList наследуется от List , а Integer наследуется от Number. Однако допуская такую возможность мы получили бы ошибку в третьей строке этого кода, ведь динамический тип IntList — ArrayList <Integer>, т.е. происходит нарушение типобезапасности (присвоение значение Float там, где ожидается Integer) и в итоге была бы получена ошибка компилятора. Дженерики созданы, чтобы избегать ошибок такого рода, поэтому существует данное ограничение. Но тем не менее это неудобное ограничение и Java поддерживает маски для его обхода.

Искусство №8: Знайте себе цену.

Каждый человек на Земле – уникален и удивителен. И вы – тоже. И каждый из нас заслуживает на большее в своей жизни. Не позволяйте никому убеждать вас в противоположном. Знайте себе цену!

Если вы по-настоящему захотите – научитесь быть невозмутимым.

Перестаньте дергаться по любому поводу и будьте честны с собой.

Жизнь слишком коротка, чтобы бесцельно тратить ее на вещи, которые не имеют значения.

Итак, зачем беспокоиться по поводу тупых и незначительных вещей, если можно сосредоточиться на действительно волшебных вещах?

Перевод статьи — The Art of Being Unf*ckwithable — 8 things you should try via КлуберФото — ERIC GIOVON

Бонус: Вы думаете о бизнесе

Наблюдая со стороны, я заметил, что ученики, которые слишком думают о бизнесе, больше сконцентрированы не на процессе программирования, а на результате. Они хотят получить “рабочее приложение”, которое поможет им реализовать их бизнес-идею. Они хотят “первыми выйти на рынок”, и длительное обучение для них — это преграда, мешающая запустить бизнес.

Размышляя о студентах, которым я не смог помочь вырасти в действительно хороших программистов, я понял, что нетерпеливость замедляла процесс обучения. И это не позволяло им действительно разобраться в технологии. Для них технология — это средство достижения результата, а не область знаний, которую нужно исследовать и получать от этого удовольствие.

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

Я бы сказал, что люди, настроенный на создание бизнеса, отлично разбираются в продажах, установлении связей и развитии бизнеса. Но при этом им труднее изучать программирование. Их природная тяга к созданию финансовых перспектив для себя и предоставлению необходимых решений для клиентов не позволяет им терпеливо работать с утомительными деталями, важными в программировании.

9 | Вы ищете “правильное” решение, не понимая, что есть спектр “хороших” и “плохих” решений

Если для вас цель программирования — это поиск единственно правильного решения, а не нескольких подходящих решений, вы никогда не станете успешным программистом.

Когда мы только начинаем изучать программирование, ученики часто спрашивают, “правильно” ли они всё делают. Ответ на такой вопрос будет: “Когда как”.

В компьютерной науке всегда важно находить компромисс. Какой вариант решения лучше в данных условиях? Всё зависит от условий и ваших целей

Если для вас программирование — это тест, в котором есть только верные и неверные ответы, вы не видите общей картины и не используете творческий потенциал. Любое решение может быть “правильным”, если вы можете обосновать его в данных условиях.

На самом деле программирование можно сравнить с написанием поэма или рассказа (или даже романа, если программа большая). В вашем коде может присутствовать эстетика и красота, которую можете разглядеть только вы и другие программисты. Причины, которые подтолкнули вас к этому решению, и ваш способ поиска этого решения важнее, чем “правильный” или “неправильный” способ. Творческое мышление позволяет вам играться с различными вариантами и возможностями, а не упираться в один-единственный способ решения. В этом и есть красота программирования: существует множество способов решения, и, держа в уме несколько вариантов, вы сможете найти самый подходящий в данной ситуации.

Мыслите творчески: Поймите, что существует множество путей решения проблемы. И со временем, благодаря опыту и знаниям, вы сформируете четкое понимание, какое решение будет лучше других. Понимание общей картины, представление разных вариантов решения и доверие своему внутреннему голосу позволят вам находить подходящие решения, которые будут приносить вам удовольствие.

Мотивация

Следующий блок кода Java иллюстрирует проблему, которая существует, когда не используются дженерики. Во-первых, он объявляет объект типа . Затем он добавляет к . Наконец, он пытается получить добавленное и преобразовать его в логическую ошибку, поскольку, как правило, невозможно преобразовать произвольную строку в целое число.

List v = new ArrayList();
v.add("test"); // A String that cannot be cast to an Integer
Integer i = (Integer)v.get(); // Run time error

Хотя код компилируется без ошибок, он выдает исключение времени выполнения ( ) при выполнении третьей строки кода. Этот тип логической ошибки может быть обнаружен во время компиляции с помощью дженериков и является основной мотивацией для их использования.

Приведенный выше фрагмент кода можно переписать с использованием дженериков следующим образом:

List<String> v = new ArrayList<String>();
v.add("test");
Integer i = (Integer)v.get(); // (type error)  compilation-time error

Параметр типа в угловых скобках объявляет, что объект состоит из (потомка общих компонентов). С универсальными шаблонами больше нет необходимости приводить третью строку к какому-либо конкретному типу, потому что результат определяется как код, сгенерированный компилятором.

Логическая ошибка в третьей строке этого фрагмента будет обнаружена как ошибка времени компиляции (с J2SE 5.0 или новее), потому что компилятор обнаружит, что возвращается вместо . Более подробный пример см. В ссылке.

Вот небольшой отрывок из определения интерфейсов и пакета :

public interface List<E> { 
    void add(E x);
    Iterator<E> iterator();
}

public interface Iterator<E> { 
    E next();
    boolean hasNext();
}

1 | Вам не хватает любопытства

Если вам не очень интересны компьютеры и технологии, вам никогда не стать успешным программистом.

Обязательным условием обучения является живой интерес к предмету, который вы изучаете. Если у вас нет интереса к технологиям, вам не хватит энергии, которая необходима для получения глубоких знаний, необходимых успешному программисту.

Мир технологий словно огромный океан интересных тем, взаимосвязанных идей и возможностей, которые могут разбудить ваше воображение. Нужна врождённая внутренняя мотивация, чтобы осмелиться погрузиться в него и исследовать всё, что можно.

Найдите свои интересы: Спросите себя, действительно ли вас интересует программирование? Если ваш честный ответ “нет”, найдите что-нибудь другое, что будет вам более интересно. Поберегите время и силы. Но если ответ “да”, заставляйте себя постоянно находить что-то новое, чего вы раньше не замечали. Познайте этот огромный океан и погрузитесь ещё глубже.

Искусство №3: Когда вас что-то вывело из себя – сделайте шаг назад и просто подышите. Оставьте все позади и двигайтесь дальше.

Есть определенные причины, по которым людей накрывает кризис среднего возраста. Также есть причины, по которым они составляют список дел или говорят: «Нужно тратить деньги на опыт, а не на вещи»

Все эти вещи указывают на одно – насколько важно сделать следующий шаг?

Когда что-то или кто-то активно треплет вам нервы – не позволяйте эмоциям взять над вами верх. Сделайте шаг назад и просто подышите. Естественно, вам придется постоять за себя, но после этого спокойно помахайте ручкой тому, кто вас достал: «Теперь ты мой враг, «дружочек», гуд бай».

В жизни каждого человека были и будут ситуации, когда аж сводит зубы от гнева, что-то шокирует и удивляет. Вы будете не раз смеяться над своим прошлым, переживать о будущем. Но все это следует оставлять позади.

Все эти глупые проблемы, которые породила наша нездоровая культура, следует скомкать и выбросить далеко в море. Эту тупую и глупую ярость и шаблонные модели поведения нездорового общества – туда же. Забудьте об этом и двигайтесь дальше.

Самое главное – вынести правильный урок изо всего этого.

Оставьте все это позади и двигайтесь к здоровому – волшебному и магическому. Главное – оно будет настоящим, а не призрачным.

5 | Вы нетерпеливы при обучении и понимании чего-либо

Если вы нетерпеливы при обучении и ожидаете, что всё будете понимать быстро и без усилий, вы никогда не станете успешным программистом.

Возможности человека не безграничны. Хотя мир развивается всё быстрее, и главной причиной этого являются компьютеры, мы не можем развиваться быстрее. Наши мозги работают с определенной скоростью. В зависимости от нашего прошлого, наших взглядов, эмоционального состояния, здоровья, все мы учимся и обрабатываем информацию с разной скоростью.

Мир технологий — это огромный океан. Вы никогда не достанете до его дна, никогда не станете абсолютным знатоком, которому больше нечего изучать. Если вы будете перегружены информацией, вы будете чувствовать необходимость “нагнать” и всегда думать, что знаете недостаточно. Если вы не можете трезво оценивать свои способности, чтобы потихоньку изучать новое, вы скоро станете думать, что двигаетесь в никуда и бросите обучение.

Наоборот, вам нужно наслаждаться самим процессом обучения. Каждая кроха знаний или новый навык, который вы получаете, должен радовать вас. Как и при решении проблем, вы должны чувствовать гордость, осознавая, что вы сделали шаг вперед, пусть и небольшой.

Осознавайте свой прогресс: В мире всегда есть, что изучать, и ваш путь в программировании никогда не закончится. Но знания нужно накапливать. Поэтому гордитесь своими знаниями, и верьте, что любое усилие, приложенное при обучении, поможет вам создать прочную базу знаний, куда бы вас ни занесла ваша карьера.

Можно исключить проверку проверенных исключений.

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

Затем мы запускаем поток в основном методе для вызова нашего метода.

Кто-то может спросить, что это значит? В обычных обстоятельствах мы должны фиксировать все проверенные исключения в методе run и не можем генерировать исключение из метода run извне, потому что метод run в классе Thread не генерирует никаких исключений, поэтому мы выбрасываем здесь все отмеченные исключения должны быть пойманы в методе выполнения. Но наша операция здесь состоит в том, чтобы обернуть проверенное исключение как непроверенное исключение, а затем бросить его в catch

Определения общих классов

Вот пример универсального класса Java, который можно использовать для представления отдельных записей (сопоставления ключей и значений) на карте :

public class Entry<KeyType, ValueType> {
  
    private final KeyType key;
    private final ValueType value;

    public Entry(KeyType key, ValueType value) {  
        this.key = key;
        this.value = value;
    }

    public KeyType getKey() {
        return key;
    }

    public ValueType getValue() {
        return value;
    }

    public String toString() { 
        return "(" + key + ", " + value + ")";  
    }

}

Этот универсальный класс можно использовать, например, следующими способами:

Entry<String, String> grade = new Entry<String, String>("Mike", "A");
Entry<String, Integer> mark = new Entry<String, Integer>("Mike", 100);
System.out.println("grade: " + grade);
System.out.println("mark: " + mark);

Entry<Integer, Boolean> prime = new Entry<Integer, Boolean>(13, true);
if (prime.getValue()) System.out.println(prime.getKey() + " is prime.");
else System.out.println(prime.getKey() + " is not prime.");

Он выводит:

grade: (Mike, A)
mark: (Mike, 100)
13 is prime.

Плюсы и минусы Java

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

Плюсы

  • Независимость — ваш код будет работать на любой платформе, которая поддерживает Java.
  • Надёжность — в немалой мере достигается благодаря строгой статической типизации.
  • Мультифункциональность.
  • Сравнительно простой синтаксис.
  • Java — основной язык для Android-разработки.
  • Объектно-ориентированное программирование (ООП) тоже приносит много выгод:
  1. параллельная разработка;
  2. гибкость;
  3. одни и те же классы можно использовать много раз;
  4. код хорошо организован, и его легче поддерживать.

Минусы

  • Низкая скорость (по сравнению с С и С++).
  • Требует много памяти.
  • Нет поддержки низкоуровневого программирования (Java — высокоуровневый язык). Например, у неё нет указателей.
  • С 2019 года обновления для бизнеса и коммерческого использования стали платными.
  • Для ООП нужен опыт, а планирование новой программы занимает много времени.

10 | Вы не уделяете внимания деталям

Если вы игнорируете детали и не замечаете мелочей, вы никогда не станете успешным программистом.

Компьютеры — точные машины. Про программировании вы должны давать компьютеры необходимые команды в точности так, как их должен понять компьютер. Если вы не сделаете этого, ничего не будет работать. Нет средней позиции, когда программа почти работает. Она либо работает, либо нет.

Это значит, что при программировании вы обязаны уделять внимание деталям. Каждому пробелу, каждой скобке, каждой точке с запятой

Если что-то не на своём месте, программа не будет работать. Если компьютер выдаёт сообщение об ошибке, вы должны, глядя на сообщение, точно понимать, о чем оно говорит. На самом деле, если вы пропустите такую мелочь, вы можете потратить несколько часов на поиск проблемы, которая произошла всего-лишь из-за опечатки.

Говорят, дьявол в деталях. И в программировании это действительно так.

Обращайте внимание на детали: Детали имеют значение, и вы должны усвоить это. Когда вы это поймете, вы будете всегда проверять, все ли символы на своих местах в вашем коде

Вы сможете грамотно выстроить свой код и использовать инструменты, которые помогут вам быстрее устранять недочеты. 

Ограничиваем дженерики сверху и снизу

Давайте немного расширим наше представление о мусоре и введём для него дополнительное свойство — массу «типичного представителя», то есть массу одной пластиковой бутылки или листка бумаги, например.

Теперь попробуем использовать эту массу в методе уже знакомого класса Box:

И получим ошибку при компиляции: мы не рассказали компилятору, что T — это какой-то вид мусора. Исправим это с помощью так называемого upper bounding — ограничения сверху:

Теперь метод getItemWeight успешно скомпилируется.

Здесь T extends Garbage означает, что в качестве T можно подставить Garbage или любой класс-наследник Garbage. Из уже известных нам классов это могут быть, например, Paper или Plastic. Так как и у Garbage, и у всех его наследников есть метод getWeight, его можно вызывать в новой версии дженерик-класса Box.

Для одного класса или интерфейса можно добавить сразу несколько ограничений. Вспомним про интерфейс для пункта приёма мусора и введём класс для метода переработки — HandleMethod. Тогда GarbageHandler можно переписать так:

В качестве границы может выступать класс, интерфейс или перечисление (enum), но не примитивный тип и не массив. При этом для интерфейсов тоже используется слово extends, а не implements: <T extends SomeInterface> вместо <T implements SomeInterface>.

Wildcards

До этого мы использовали для параметров типов буквенные имена, но в Java есть и специальный символ для обозначения неизвестного типа — «?». Его принято называть wildcard, дословно — «дикая карта».

Термин wildcard пришёл в программирование из карточной игры. В покере, например, так называют карту, которая может сыграть вместо любой другой. Джокер — известный пример такой «дикой карты».

Wildcard нельзя подставлять везде, где до этого мы писали буквенные обозначения. Не получится, например, объявить класс Box<?> или дженерик-метод, который принимает такой тип:

Wildcards удобно использовать для объявления переменных и параметров методов совместно с классами из Java Collection Framework — здесь собраны инструменты Java для работы с коллекциями. Если вы не очень хорошо знакомы с ними, освежите знания, прочитав эту статью.

В примере ниже мы можем подставить вместо «?» любой тип, в том числе Paper, поэтому строка успешно скомпилируется:

Wildcards можно применять для ограничений типов:

Это уже знакомое нам ограничение сверху, upper bounding, — вместо «?» допустим Garbage или любой его класс-наследник, то есть Paper подходит.

Но можно ограничить тип и снизу. Это называется lower bounding и выглядит так:

Здесь <? super Garbage> означает, что вместо «?» можно подставить Garbage или любой класс-предок Garbage. Все ссылочные классы неявно наследуют класс Object, так что в правой части ещё может быть ArrayList<Object>.

4 | Вы не чувствуете удовлетворения после решения проблемы.

Если вы не испытываете радости и чувства выполненного долга после решения проблемы, вы никогда не станете успешным программистом.

Отсутствие “позитива” после успешного решения проблемы относится к предыдущему признаку — быстрому отказу от поиска решения. Когда устранения багов и недочетов становится бесконечной рутиной, вы забываете об удовольствии, которые приходит при решении проблемы.

Когда вы находите решение, вы получаете необходимую дозу дофамина. Это похоже на эмоции, которые вы испытываете, проходя уровень в видеоигре, или решая судоку или кроссворд. Мы все знаем, что если после долгого и сложного решения задачи, вы все-таки одерживаете верх, то испытываете положительные эмоции. Но если вы больше их не испытываете, или вообще никогда не придавали этому значения, вы не испытаете удовольствия от программирования. Если программирование для вас — скучная работа, где вам просто нужно достичь результата легчайшим способом, вы никогда не станете действительно успешным программистом.

Радуйтесь своим успехам: Когда вы решаете проблему, над которой долго бились, независимо от её сложности, гордитесь выполненной работой, отдыхайте и поздравляйте себя. Дайте чувству удовлетворения проникнуть в вас и наполнить энергией для решения следующей проблемы.

Преимущества дженериков в Java

1. Возможность повторного использования Кода

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

2. Кастинг отдельных типов не требуется

В принципе, вы каждый раз восстанавливали информацию из ArrayList, вам нужно ее типизировать. Типизация при каждой задаче восстановления-это серьезная мигрень. Чтобы искоренить этот подход, были введены дженерики.

3. Реализация нестандартного алгоритма

Он может вычислять алгоритмы, которые работают с различными типами элементов, которые также являются типобезопасными.

Это было все о преимуществах дженериков Java. На этом мы подходим к концу этой статьи о дженериках в Java. Я надеюсь, что вы нашли его информативным и помогли вам в понимании универсалий Java.

У вас есть к нам вопрос? Пожалуйста, укажите это в разделе комментариев этой статьи, и мы свяжемся с вами как можно скорее.

Оригинал: “https://www.codementor.io/@nehavaidya/what-is-generics-in-java-a-beginners-guide-to-learn-generics-w371wnbcv”

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: