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

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

java generics описание

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


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

Разберем простой пример применения обобщения к обычному классу на рисунке ниже. И уже затем приступим к детальному рассмотрению всех тонкостей и нюансов Java Generic.

generic class java

Обратите внимание на то, каким образом происходит объявление класса Pair. Сразу после имени класса открываются угловые скобки, в которых указывается буква T. Она представляет собой своеобразный заполнитель, который в процессе создания экземпляра данного класса будет заменен конкретным типом. Выглядит это следующим образом: Pair<Integer> obj = new Pair< Integer >(). Следует отметить, что вместо T можно указывать любую букву, но, как правило, используют T, V или E.

Примечание: начиная с восьмой версии Java, указав целевой тип при объявлении ссылки, угловые скобки в конструкторе можно оставить пустыми. Так приведенный выше пример можно переписать следующим образом: Pair<Integer> obj = new Pair<>().


Когда класс объявлен таким образом, далее в его теле вместо конкретных типов полей, ссылок и возвращаемых методами объектов можно использовать эту букву. Поскольку T при создании объекта класса заменяется конкретным типом, поля first и second в данном случае будут иметь тип Integer.

Следуя логике, аргументы firstItem и secondItem, передающиеся соответствующему конструктору, также должны иметь тип Integer или его подкласса. Если вы попытаетесь передать тип данных, отличающийся от того, что был указан при создании объекта, компилятор не пропустит эту ошибку. Так, конструктор с аргументами при создании объекта будет иметь следующий вид: Pair<Integer> obj = new Pair<>(new Integer(1), new Integer(2)). То же самое относится к аргументам методов setFirst и setSecond. И как вы уже, наверное, догадались, методы getFirst и getSecond будут возвращать значения типа Integer.

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

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

java generic

Как видим, при создании экземпляра такого класса в угловых скобках следует указывать то же количество типов, что и параметров. Если вы знакомы с таким видом структуры данных, как Map, то вы могли заметить, что там используется точно такой же принцип. Там первый аргумент определяет тип ключа, а второй – тип значения. Следует отметить, что типы передаваемых при создании объекта аргументов могут совпадать. Так, следующее объявления экземпляра класса Pair является абсолютно корректным: Pair<String, String> obj.


Некоторые особенности обобщений

Перед тем как идти далее, следует отметить, что компилятор Java не создает никаких различных версий класса Pair. На самом деле в процессе компиляции вся информация об обобщенном типе удаляется. Вместо этого выполняется приведение соответствующих типов, создавая специальную версию класса Pair. Однако в самой программе по-прежнему существует единственная обобщенная версия данного класса. Этот процесс называется в Java Generic очистка типа.

Отметим важный момент. Ссылки на разные версии одного и того же java generic класса не могут указывать на один и тот же объект. То есть, допустим, у нас есть две ссылки: Pair<Integer> obj1 и Pair<Double> obj2. Следовательно, в строке obj1 = obj2 возникнет ошибка. Хотя обе переменные относятся к типу Pair<T>, объекты, на которые они ссылаются, разные. Это яркий пример обеспечения безопасности типов в Java Generic.

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

Важно знать, что обобщения могут применяться только к ссылочным типам, то есть передаваемый параметру generic class java аргумент обязательно должен быть типом класса. Такие простые типы, как, например, double или long, передавать нельзя. Иными словами, следующая строка объявления класса Pair недопустима: Pair<int> obj. Тем не менее данное ограничение не представляет серьезной проблемы, так как в Java для каждого примитивного типа имеется соответствующий класс-оболочка. Строго говоря, если в классе Pair вы хотите инкапсулировать целочисленное и логическое значение, автоупаковка сделает все за вас: Pair<Integer, Boolean> obj = new Pair<>(25, true).

Еще одним серьезным ограничением является невозможность создания экземпляра параметра типа. Так, следующая строка вызовет ошибку компиляции: T first = new T(). Это очевидно, поскольку вы заранее не знаете, будет ли в качестве аргумента передаваться полноценный класс или абстрактный, или вовсе интерфейс. То же самое касается создания массивов.

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

Довольно часто возникают ситуации, когда необходимо ограничить перечень типов, которые можно передавать в качестве аргумента java generic классу. Допустим, что в нашем классе Pair мы хотим инкапсулировать исключительно числовые значения для дальнейших математических операций над ними. Для этого нам необходимо задать верхнюю границу параметра типа. Реализуется это при помощи объявления суперкласса, наследуемого всеми аргументами, передающимися в угловых скобках. Выглядеть это будет следующим образом: class Pair<T extends Number>. Таким способом компилятор узнает, что вместо параметра T можно подставлять либо класс Number либо один из его подклассов.

Это распространенный прием. Такие ограничения часто используются для обеспечения совместимости параметров типа в одном и том же классе. Рассмотрим пример на нашем классе Pair: class Pair<T, V extends T>. Здесь мы сообщаем компилятору, что тип Т может быть произвольным, а тип V обязательно должен быть либо типом Т, либо одним из его подклассов.

Ограничение «снизу» происходит точно таким же образом, но вместо слова extends пишется слово super. То есть объявление class Pair<T super ArrayList> говорит о том, что вместо Т может быть подставлен либо ArrayList, либо любой класс или интерфейс, которые он наследует.

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

В Java обобщения можно применять не только в отношении классов, но и методов. Так, обобщенный метод может быть объявлен в обычном классе.

generic методы java

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

В случае конструктора все делается аналогично:

java generic очистка типа

Угловые скобки в этом случае ставятся перед названием конструктора, так как он не возвращает никакого значения. Результатом работы обеих программ будет:

Integer

String

Язык Add Constraint SQL
SQL — это полнофункциональный язык, который позволяет создавать БД, таблицы, вводить и корректировать данные, оформлять представления, индексы и отчеты . Если у вас есть несколько минут, просмотрите информацию про Tutorial SQL, которая даст начало ...
далее
Java: работа с файлами - запись, чтение, удаление
Подавляющее большинство программ написанных на Java, так или иначе взаимодействуют с файлами, храня и доставая оттуда нужную информацию. Для операций с файлами в Java существуют специализированные классы, о которых в этой статье и пойдет речь.
далее
OpenGL: как обновить пакет драйверов простейшими методами?
Несомненно, многие геймеры знают, что для корректной работы таких известных игр, как Minecraft или CS, одним из самых основных условий является наличие в системе установленных последних версий драйверов OpenGL. Как обновить этот пакет драйверов, ...
далее
Программирование: Java. Типы данных
Язык программирования содержит некоторые заранее определенные встроенные типы и позволяет программистам определять свои собственные, пользовательские. В Java типы данных делятся на примитивные и ссылочные.
далее
Язык программирования Java: с чего начать изучение. Где применяется ...
"Джава" - это язык программирования широкого назначения. С его помощью разрабатываются программы на смартфоны и планшеты, компьютеры. Особенность таких приложений - кроссплатформенность. Существует несколько семей технологии Java: SE, EE, ...
далее
Portable - что это значит? Программы с отметкой Portable
Среди компьютерного софта portable-программы занимают если не лидирующее положение, то, по крайней мере, одно из первых мест. Связано это не только с удобством их использования и запуска с любого носителя информации, но и с удобством транспортировки в плане того, что программа может быть записана на диск или обычную флешку. Итак, попробуем разобраться в основной теме «Portable soft - что это?».
далее
Portable - что это значит? Программы с отметкой Portable
Java: исключения и их обработка
Как работают исключения в Java. Каким образом происходит их отлов и обработка, наиболее часто встречающиеся варианты и описание к ним.
далее
Java: исключения и их обработка
Реверс-инжиниринг для начинающих. Защита Android-приложений от реверс-инжиниринга
Порой кто-то хочет посмотреть, а какая же начинка в определённой программе? Тогда ему приходится использовать реверс-инжиниринг. Что это такое? Как действует? Каким образом происходит этот процесс? Обо всём этом вы сможете узнать из данной статьи.
далее
Реверс-инжиниринг для начинающих. Защита Android-приложений от реверс-инжиниринга
System out println java — консольный вывод
Подробное описание работы метода System.out.println() в Java. Функции реализации вывода строк, переменных, спецификаторов и escape-последовательностей. Возможности сокращенного ввода инструкций для вывода данных.
далее
System out println java — консольный вывод
Java. String: способы, примеры
Java String или строки в Java являются основными носителями текстовой информации, поэтому этот класс популярен и часто используется. В пакете Java.lang есть несколько классов для работы со строками - это StringBuffer и StringBuilder. Они объявлены как final - это говорит о том, что от этих классов невозможно наследоваться. Для того чтобы проверить это, откроем редактор и напишем слово string, а затем перейдем в сам класс.
далее
Java. String: способы, примеры