что нельзя параметризовать java

Параметризованные классы Java

К наиболее важным новшествам версии языка J2SE 5 можно отнести появление параметризованных (generic) классов и методов, позволяющих использовать более гибкую и в то же время достаточно строгую типизацию, что особенно важно при работе с коллекциями. Применение generic-классов для создания типизированных коллекций будет рассмотрено в главе «Коллекции». Параметризация позволяет создавать классы, интерфейсы и методы, в которых тип обрабатываемых данных задается как параметр.

Приведем пример generic-класса с двумя параметрами:

/*пример # 9 : объявление класса с двумя параметрами : Subject.java */

public class Subject <

public Subject(T2 ids, T1 names) <

Здесь T1, Т2 – фиктивные объектные типы, которые используются при объявлении членов класса и обрабатываемых данных. При создании объекта компилятор заменит все фиктивные типы на реальные и создаст соответствующий им объект. В качестве параметров классов запрещено применять базовые типы.

Объект класса Subject можно создать, например, следующим образом:

new Subject (ch, 71D );

В объявлении sub2 имеет место автоупаковка значения 71D в Double.

Параметризированные типы обеспечивают типовую безопасность.

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

/*пример # 10 : создание и использование объектов параметризованного

public class Optional <

public Optional(T value) <

public void setValue(T val) <

public String toString() <

return value.getClass().getName() + » » + value;

public static void main(String[] args) <

int v1 = ob1.getValue();

String v2 = ob2.getValue();

//ob1 = ob2; //ошибка компиляции – параметризация не ковариантна

Optional ob3 = new Optional();

ob3.setValue(«Java SE 6»);

тип объекта, а не тип параметризации */

В результате выполнения этой программы будет выведено:

java.lang.String Java SE 6

В рассмотренном примере были созданы объекты типа Optional: ob1 на основе типа Integer и ob2 на основе типа String при помощи различных конструкторов. При компиляции вся информация о generic-типах стирается и заменяется для членов класса и методов заданными типами или типом Object, если параметр не задан, как для объекта ob3. Такая реализация необходима для обеспечения совместимости с кодом, созданным в предыдущих версиях языка.

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

public class OptionalExt <

Такая запись говорит о том, что в качестве типа Т разрешено применять только классы, являющиеся наследниками (суперклассами) класса Tип, и соответственно появляется возможность вызова методов ограничивающих (bound) типов.

Часто возникает необходимость в метод параметризованного класса одного допустимого типа передать объект этого же класса, но параметризованного другим типом. В этом случае при определении метода следует применить метасимвол ?. Метасимвол также может использоваться с ограничением extends для передаваемого типа.

/*пример # 11 : использование метасимвола в параметризованном классе: Mark.java, Runner.java */

public Mark(T value) <

/* вместо */ // public boolean sameAny(Mark ob) <

public boolean sameAny(Mark ob) <

return roundMark() == ob.roundMark();

public boolean same(Mark ob) <

return getMark() == ob.getMark();

public static void main(String[] args) <

Mark md = new Mark (71.4D);//71.5d

Mark mi = new Mark (71);

В результате будет выведено:

Метод sameAny(Mark ob) может принимать объекты типа Mark, инициализированные любым из допустимых для этого класса типов, в то время как метод с параметром Mark мог бы принимать объекты с инициализацией того же типа, что и вызывающий метод объект.

Для generic-типов существует целый ряд ограничений. Например, невозмож­но выполнить явный вызов конструктора generic-типа:

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

По аналогичным причинам generic-поля не могут быть статическими, статические методы не могут иметь generic-параметры или обращаться к generic-полям, например:

Читайте также:  ритуал на полнолуние для привлечения любви

/*пример # 12 : неправильное объявление полей параметризованного класса: Failed.java */

Источник

Core Java

Курс лекций. Лекция 6

Иван Пономарёв, КУРС/МФТИ

До появления дженериков

После появления дженериков

Определяем собственный параметризованный класс

Определение и использование

Generic methods

Другой пример

Промежуточные выводы

Использование параметризованных классов — простое (просто укажите параметры, List )

Использование параметризованных методов — ещё проще: type inference: Manager m = getRandomItem(…​);

Написание собственных параметризованных классов и методов — задачка более сложная.

Bounded types

Intersection types

Реализация дженериков

Появились в Java 5

Стояла задача обратной совместимости

Generics — возможность языка, а не платформы

Type Erasure, будь он неладен!

Сырые типы

Generic Type (source)

Raw Type (compiled)

Ограниченные типы вместо Object

Generic Type (source)

Raw Type (compiled)

Вызовы методов

Source code

Compiled

Bridge methods для сохранения полиморфизма

Source code

Compiled

Итог: как это работает

Параметризованных классов в JVM нет, только обычные классы и методы.

Типовые параметры заменяются на Object или на свою границу.

Для сохранения полиморфизма добавляются связывающие методы (bridge methods).

Сведение типов добавляется по мере необходимости.

Никогда не употребляйте сырые типы

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

Java5 вышла в 2004 году.

Понимание дженериков в Джаве — это не про то, что с ними делать можно, а про то, что с ними делать нельзя.

Стирание типов → невозможность определить параметр типа в Runtime

Стирание типов до Object → невозможность использовать примитивные типы в качестве параметров

Примитивы и дженерики

День сегодняшний: нужна производительность? — пишем специальные реализации.

В стандартной библиотеке:

В специализированных библиотеках вроде fastutil:

HashMap → Int2ObjectMap (ВНИМАНИЕ: реальная потребность в таких библиотеках возникает редко!!)

День завтрашний: Project Valhalla, specialized generics. Решит проблему раз и навсегда.

Нельзя инстанцировать типы-параметры

Решается с помощью метакласса и рефлексии (о которой речь впереди)

Тем более нельзя инстанцировать массив типа-параметра

Решается передачей параметра, например, в ArrayList:

Массивы и дженерики — лютые враги

Забьём значения кувалдой и устроим heap pollution

Varargs — всё равно массив…​

Тот же heap pollution, что и в прошлом примере:

Компилятор что-то предчувствует…​

Чтобы успокоить компилятор, надо поставить аннотацию @SafeVarargs :

…​и компилятор успокоится.

Зачем?!

Всё потому, что иметь varargs с параметризованными типами удобно.

Collections.addAll(Collection c, T…​ elements)

EnumSet.of(E first, E…​ rest)

Если вести себя хорошо, можно ставить @SafeVarargs, и всё будет хорошо:

Не записывать ничего в элементы массива,

Не раздавать ссылку на массив параметров наружу.

Нельзя параметризовать

ловля исключений — это проверка их типов,

дальше сырых типов мы в рантайме проверить не можем.

Инстанцируется по месту, не может быть несколько классов, параметризованных по-разному.

Параметры типов нельзя использовать в статическом контексте

Нельзя реализовывать разные параметризации одного и того же интерфейса

Source code

Compiled

Ковариантность массивов vs инвариантность дженериков

Реальная картина

Как быть, если хочется такого?

Так не получится…​

Wildcard Types

В общем, addAllTo реализовать не получится…​

В обратную сторону (контравариантные типы)

Unbounded wildcard

Класть можем только null.

Мнемоническое правило

PECS

Producer Extends, Consumer Super

Правила использования wildcard-типов

Используются в аргументах методов и локальных переменных.

Невидимы пользователю API, не должны возвращаться.

Их цель — принимать те аргументы, которые надо принимать, и отвергать те аргументы, которые надо отвергать.

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

Wildcard Capture

Метод с type capture

Recursive Generics

Что почитать-посмотреть

J. Bloch, Effective Java, 3rd ed. Chapter 5 — Generics. Addison-Wesley, 2018

Читайте также:  какой подарок можно сделать на свадьбу молодоженам

Источник

BestProg

Java. Обобщения (шаблоны). Параметризованные типы. Обобщенные классы

Содержание

Поиск на других ресурсах:

1. Что такое «обобщение» (шаблон) в языке Java? Что такое параметризованный тип? Особенности применения обобщений

Обобщение – это механизм построения программного кода для некоторого типа с произвольным именем с целью его дальнейшего конвертирования (преобразования) в другой конкретный ссылочный тип. Реализацию конвертирования из обобщенного типа в другой (конкретный) осуществляет компилятор.

2. Преимущества применения обобщений

Использование обобщений в языке Java дает следующие преимущества:

3. Общая форма объявления обобщенного класса и объявление ссылки на обобщенный класс

Чаще всего обобщенный класс оперирует с одним типом. В этом случае общая форма класса имеет вид:

Общая форма объявления ссылки на обобщенный класс следующая

Например, если в программе объявить класс, который получает параметром тип T

то в этом классе можно реализовывать переменные и методы, которые имеют тип T

После объявления, использование вышеприведенного класса для типа Integer будет следующим

В вышеприведенном объявлении тип Integer есть аргументом типа.

Создание экземпляра класса для типа Double следующее

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

4. Какие типы запрещается использовать в обобщенных классах в качестве параметризованных типов?

То есть, если задан класс

то объявить экземпляр типа int или другого базового типа не удастся

5. Пример обобщенного класса, который реализует метод поиска элемента в двумерной матрице

Метод SearchKey() получает следующие параметры:

6. Пример реализации метода, который осуществляет циклический сдвиг в массиве обобщенного типа Type

Результат работы программы

7. Пример класса, который получает два параметризованных типа

Источник

Дженерики Java

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

Классы, интерфейсы или методы, имеющие дело с параметризованными типами, называются параметризованными или обобщениями, параметризованными (обобщенными) классами или параметризованными (обобщёнными) методами.

Обобщения добавили в язык безопасность типов.

1. Параметризованные классы

Следующий пример демонстрирует использование параметризованного класса, который описывает матрицу:

В объявлении Matrix integerMatrix Integer является аргументом типа.

Дженерики работают только с объектами! Следующий код является неправильным:

Т обозначает имя параметра типа. Это имя используется в качестве заполнителя вместо которого в дальнейшем подставляется имя конкретного типа, передаваемого классу Matrix при создании объекта. Это означает, что обозначение Т применяется в классе Matrix всякий раз, когда требуется параметр типа. Всякий раз, когда объявляется параметр типа, он указывается в угловых скобках.

Обобщенные типы отличаются в зависимости от типов-аргументов. Следующий код не допустим:

Обобщенный класс может быть объявлен с любым количеством параметров типа. Например:

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

Указывая параметр типа, можно наложить ограничение сверху в виде верхней границы, где объявляется супер класс, от которого должны быть унаследованы все аргументы типов. С этой целью вместе с параметром указывается ключевое слово extends :

Параметр типа Т может быть заменен только указанным супер классом или его подклассами.

Рассмотрим пример использования ограниченного типа:

В виде ограничения можно накладывать не только тип класса, но и тип интерфейса:

Ограничение может включать в себя как тип класса, так и типы одного или нескольких интерфейсов:

3. Применение метасимвольных аргументов

Представьте, что мы хотим добавить метод для сравнения средних значений массивов в класс Average из примера 3. Причем типы массивов могут быть разные:

Но это не сработает, так как в этом случае метод sameAvg будет принимать аргументы только того же типа, что и существующий объект:

Читайте также:  Как называются внуки родной сестры

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

4. Параметризованные методы и конструкторы

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

Но можно объявить параметризованный метод, в котором непосредственно используется один или несколько параметров типа. Более того, можно объявить параметризованный метод, входящий в не параметризованный класс. Например:

Конструкторы также могут быть обобщенными, даже если их классы таковыми не являются. Например:

5. Параметризованные интерфейсы

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

6. Иерархии параметризованных классов

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

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

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

7. Использование оператора instanceof c параметризованными классами

8. Ограничения присущие обобщениям

Обобщениям присущи некоторые ограничения. Рассмотрим их:

1. Нельзя создавать экземпляр по параметру типа. Ни обычный объект, ни массив:

2. Нельзя создать массив специфических для типа обобщенных ссылок:

3. Нельзя создавать обобщенные статические переменные и методы. Но объявить статические обобщенные методы со своими параметрами типа все же можно:

Источник

Вопрос по дженерикам метода и ограничению переменных типов

Сейчас активно изучаю (или даже разбираю) известное пособие Хорстмена и Корнелла по Java2. В данный момент остановился на параметризации. Дошел до пункта «Обобщенные методы» и следующий за ним «Ограничения переменных типов». И в ближайшем листинге среди прочего кода появляется такая сигнатура:

Я понимаю, что в методе применяется метод compareTo(), принадлежащий интерфейсу Comparable и поэтому мы должны «защитить» наш метод от того, чтобы туда не затесался класс, который не реализует данный интерфейс. Ок, понятно. Но почему бы тогда нельзя было написать:

С другой стороны, возможно имелось в виду, что это не объект класса Pair должен возвращать метод, а объект любого класса, реализующий Comparable? Тогда почему не написать так:

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

2 ответа 2

Вы хотите развёрнутых ответов? Их есть у меня! Немного теории по параметризованным методам.

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

В этом случае тип T определяется в момент вызова статического метода по типу передаваемого аргумента.

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

Теперь непосредственно к вашему вопросу. Нельзя просто написать

Почему нельзя написать

Источник

Портал про кино и шоу-биз