Java Generics: описание и методы

Java GenericsЯзык программирования Java, начиная с момента своего появления, претерпел множество изменений, которые, несомненно, привнесли в его функциональность положительные моменты. Одним из самых значимых изменений является введение Java Generic, или, говоря иначе, обобщения. Эта функциональность сделала язык не только универсальнее и гибче, но и более безопасным с точки зрения приведения типов данных. Все дело в том, что до введения дженериков создавать обобщенный код в Java можно было, только оперируя ссылками типа Object. Ссылки такого рода можно присваивать любому объекту. Все классы в Java являются неявными наследниками класса Object. Однако подобный подход является потенциальным источником ошибок, связанных с безопасностью типов при явном преобразовании объекта из Objet к целевому типу. Все приведения в случае использования обобщений выполняются неявно и автоматически. Это исключает потенциальную возможность появления ошибок.

Java Generics: пример и описание

Давайте разберем простой пример применения обобщения к обычному классу. Затем приступим к более детальному рассмотрению всех тонкостей и особенностей Java Generic. Прежде всего, стоит обратить внимание на то, каким образом происходит объявление класса Pair. Сразу после имени класса открываются угловые скобки, где указывается буква T. Данная буква представляет собой своеобразный заполнитель, который будет заменен конкретным типом в процессе создания экземпляра данного класса. Это выглядит примерно следующим образом:

Pairobj = newPair<Integer>(). Необходимо отметить, что вместо T можно указать любую букву, однако, как правило, используются T, V, E. Начиная с восьмой версии Javaпосле указания целевого типа при объявлении ссылки, угловые скобки в конструкторе можно оставить пустыми. Приведенный выше пример также можно переписать так: Pairobj = newPair<>(). Если класс объявлен таким способом, то далее вместо конкретных типов ссылок, полей и возвращаемых методами объектов в его теле можно использовать эту букву.  Так как T при создании объекта класса будет заменена конкретным типом, поля first и second в данном случае имеют тип Integer. Следуя данной логике, аргументы firstItem и second Item, которые передаются соответствующему конструктору, должны иметь тип Integer или его подкласс. Если вы предпринимаете попытку передать тип данных, отличный от того, который был указан при создании объекта, компилятор не пропустит такую ошибку. Конструктор с аргументами при создании объекта будет иметь примерно следующий вид: PairObj = newPair<>(newInteger(1), newInteger (2)). Это же относится и к аргументам методов set Second и set First.Как вы уже, наверное, догадались, методы get Second и get First будут возвращать значения типа Integer.

Обобщенный класс с несколькими параметрами типов

В обобщенных классах также существует возможность объявления нескольких параметров типа, задаваемых в угловых скобках через запятую. При создании экземпляра данного класса в угловых скобках необходимо указывать то же количество типов, что и параметров. Если вам знаком такой вид структуры данных, как Map, то вы можете заметить, что там используется абсолютно тот же принцип. Там первый тип определяет тип ключа, а второй – тип значения. Необходимо отметить, что типы аргументов, передаваемых при создании объекта, могут совпадать. Так, следующее объявление экземпляра класса Pair является совершенно корректным – Pairobj.

Особенности обобщений

Прежде чем идти далее, необходимо отметить, что компилятор Java не создает различных версий класса Pair.В процессе компиляции вся информация об обобщенном типе на самом деле удаляется. Вместо этого осуществляется приведение соответствующих типов с созданием специальной версии класса Pair. В самой программе  по-прежнему имеется единственная обобщенная версия данного класса. Данный процесс в Java Generic носит название очистки типа. Стоит отметить один важный момент. Ссылки на разные версии одного и того же класса Java generic не могут указывать на один и тот же объект. Предположим, у нас имеется две ссылки – pairobj1 и Pairobj2. Таким образом, в строке obj1=obj2 возникнет ошибка. Несмотря на то, что обе переменные относятся к классу Pair, они ссылаются на разные объекты. Это яркий пример обеспечения безопасности типов в Java Generic.

Ограничения, накладываемые на обобщенные классы

Важно также знать, что обобщения могут применяться только по отношению к ссылочным типам. Это значит, что аргумент, передаваемый параметру genericclassjava обязательно должен быть типом класса. Простые типы, вроде long и double,нельзя передавать. Иначе говоря, следующая строка объявления класса Pair является недопустимой – Pairobj.Однако данное ограничение не представляет серьезной проблемы, поскольку в Java для каждого примитивного типа имеется соответствующий класс-оболочка. Иначе говоря, если вы хотите инкапсулировать целочисленное и логическое значение в классе Pair, автоупаковка сделает это за вас – Pairobj = newPair<> (25, true). Невозможность создания экземпляра параметра типа является еще одним серьезным ограничением. Следующая строка вызовет ошибку компиляции: Tfirst=newT(). Это очевидно, так как заранее вам неизвестно, будет ли в качестве аргумента передаваться абстрактный или полноценный класс или полный интерфейс. Это также касается и создания массивов.

Ограниченные типы

Очень часто возникают ситуации, при которых требуется ограничить перечень типов, которые можно передавать классу в качестве аргумента javageneric. Предположим, что в нашем классе Pair мы хотим инкапсулировать только числовые значения для осуществления над ними дальнейших математических операций. Для этого нам нужно задать верхнюю границу параметра типа. Это реализуется при помощи объявления супер класса, который наследуется всеми аргументами, передающимися в угловых скобках. Это будет выглядеть следующим образом: class Pair. Таким образом, компилятор узнает, что вместо параметра T можно подставить либо класс Number, либо один из его подклассов. Это довольно распространенный прием. Часто такие ограничения используются для обеспечения совместимости параметров типа в одном и том же классе. Давайте рассмотрим пример на классе Pair: classPair. Здесь компилятору сообщается, что тип T может быть произвольным, а тип V обязательно должен быть либо типом T, либо одним из его подклассов. Ограничение снизу осуществляется точно так же, однако вместо слова extends пишется слово super. Таким образом, объявление classPair говорит о том, что вместо T может быть представлен или ArrayListили любой интерфейс или класс, который он наследует.

Generic методы и конструкторы

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *