Какой результат выполнения данной части кода?
Anonymous Quiz
14%
1
62%
2
5%
Ошибка времени выполнения
20%
Ошибка компиляции
👍8
Как используется @Deprecated?
Этой аннотацией помечают код, который устарел и не должен быть более использован. Классы, которые используют или переопределяют @Deprecated элементы, будут компилироваться с warning-ом.
Имеет retention RUNTIME, что значит, что фреймворки могут динамически проверять наличие аннотации на элементе с помощью Reflection API.
Начиная с Java 9 у этой аннотации появились опциональные параметры – строка since и булево значение forRemoval. В since указывается версия вашего приложения, начиная с которой элемент считается устаревшим. Значение true в forRemoval предупреждает, что со следующей мажорной версии этот элемент будет удален. Такое нововведение связано с изменением политики устаревания – с Java 9 и устаревшие элементы самой JDK тоже могут удаляться в будущих версиях.
Обычно, когда элемент помечают устаревшим, причины устаревания и дальнейшие рекомендации указывают в его Javadoc-документации под тегом @deprecated.
Этой аннотацией помечают код, который устарел и не должен быть более использован. Классы, которые используют или переопределяют @Deprecated элементы, будут компилироваться с warning-ом.
Имеет retention RUNTIME, что значит, что фреймворки могут динамически проверять наличие аннотации на элементе с помощью Reflection API.
Начиная с Java 9 у этой аннотации появились опциональные параметры – строка since и булево значение forRemoval. В since указывается версия вашего приложения, начиная с которой элемент считается устаревшим. Значение true в forRemoval предупреждает, что со следующей мажорной версии этот элемент будет удален. Такое нововведение связано с изменением политики устаревания – с Java 9 и устаревшие элементы самой JDK тоже могут удаляться в будущих версиях.
Обычно, когда элемент помечают устаревшим, причины устаревания и дальнейшие рекомендации указывают в его Javadoc-документации под тегом @deprecated.
👍17
Даны следующие классы:
Anonymous Quiz
5%
Исключение RuntimeException.
52%
Исключение ClassCastException.
24%
Успешный запуск и отработка.
19%
Ошибка компиляции.
👍31🍌1
Перечислите все мета-аннотации
Мета-аннотации – это аннотации для объявления других аннотаций. Вообще мета-аннотациями можно назвать любую аннотацию с таргетом ANNOTATION_TYPE, но основных в Java существует 5. Они определяют для аннотации:
• @Retention – переживет ли компиляцию.
• @Inherited – применяется к наследникам.
• @Repeatable – применяема несколько раз к одному и тому же элементу.
• @Target – контексты, в которых можно применять.
• @Deprecated – не должна использоваться.
Мета-аннотации – это аннотации для объявления других аннотаций. Вообще мета-аннотациями можно назвать любую аннотацию с таргетом ANNOTATION_TYPE, но основных в Java существует 5. Они определяют для аннотации:
• @Retention – переживет ли компиляцию.
• @Inherited – применяется к наследникам.
• @Repeatable – применяема несколько раз к одному и тому же элементу.
• @Target – контексты, в которых можно применять.
• @Deprecated – не должна использоваться.
👍22🕊2❤1
Что выведет на экран следующий код?
Anonymous Quiz
55%
TT.methodA 1
15%
TT.methodA 2
10%
TT.methodA 0
7%
Ошибка выполнения
14%
Ошибка компиляции
👍24❤4
Что такое Type Erasure?
Компилятор удаляет из байткода класс-файла информацию о типах-дженериках. Этот процесс и называется стирание типов (type erasure). Он появился в Java 5 вместе с самими дженериками. Такое решение позволило сохранить обратную совместимость без перекомпилляции кода Java 4.
Стирание состоит из трех действий:
🔘 Если параметры ограничены (bounded), вместо типа-параметра в местах использования подставляется верхняя граница, иначе Object;
🔘 В местах присвоения значения типа-параметра в переменную обычного типа добавляется каст к этому типу;
🔘 Генерируются bridge-методы.
Информация о типах стирается только из методов и полей, но остается в метаинформации самого класса. Получить эту информацию в рантайме можно с помощью рефлекшна, методом Field#getGenericType.
Тип со стертой информацией о дженериках называется «Non-reifiable».
Стирание типов позволяет не создавать при применении дженериков новые классы, в отличие от, например, шаблонов C++.
Компилятор удаляет из байткода класс-файла информацию о типах-дженериках. Этот процесс и называется стирание типов (type erasure). Он появился в Java 5 вместе с самими дженериками. Такое решение позволило сохранить обратную совместимость без перекомпилляции кода Java 4.
Стирание состоит из трех действий:
🔘 Если параметры ограничены (bounded), вместо типа-параметра в местах использования подставляется верхняя граница, иначе Object;
🔘 В местах присвоения значения типа-параметра в переменную обычного типа добавляется каст к этому типу;
🔘 Генерируются bridge-методы.
Информация о типах стирается только из методов и полей, но остается в метаинформации самого класса. Получить эту информацию в рантайме можно с помощью рефлекшна, методом Field#getGenericType.
Тип со стертой информацией о дженериках называется «Non-reifiable».
Стирание типов позволяет не создавать при применении дженериков новые классы, в отличие от, например, шаблонов C++.
👍28❤1❤🔥1
Что напечатает следующий код?
Anonymous Quiz
38%
Код не скомпилируется
2%
Код скомпилируется, но ничего не напечатает
50%
Код скомпилируется и напечатает 3
5%
Код скомпилируется, но во время выполнения возникнет исключение
4%
Ничего из вышеперечисленного
👍25🍾2🌚1
Как ограничивается тип generic параметра?
В объявлении дженерик-параметра класса или метода может быть указана его верхняя граница (bound)
Помимо ограничения возможных применяемых типов, bounded-параметр дает право использовать в реализации методы и поля типа-ограничителя – он будет как минимум предком фактического типа. Это достигается стиранием типа-параметра до верхней границы.
Тип-параметр может иметь несколько верхних границ, то есть границу-пересечение типов: <T extends Comparable & Serializable>. Стирание произойдет до первой из границ, остальные послужат только ограничением вариантов фактического типа. Поэтому граница-класс, при наличии, должна быть указана раньше границ-интерфейсов.
При указании значения дженерик-параметра переменной может быть использован вайлдкард – символ ?. Вайлдкард значит, что мы не собираемся использовать информацию о конкретном типе, этот тип может быть любым. Это не то же самое, что не указать дженерик параметр совсем.
Для вайлдкарда также как и для объявления типа-параметра можно обозначить верхнюю границу. Но в отличие от объявления здесь нельзя использовать пересечение типов, по крайней мере пока.
Кроме того в случае вайлдкарда можно задать нижнюю границу
В объявлении класса или метода использование super запрещено, так как не имеет смысла.
Разобраться в использования ограниченных вайлдкардов поможет это видео.
Хороший API должен уметь эффективно работать с классами-наследниками, то есть быть ко- или контравариантным где это необходимо. При этом без bounded вайлдкардов не обойтись. Чтобы запомнить, какая граница нужна в каких случаях, Joshua Bloch предложил мнемонику PECS: Producer-extends, Consumer-super
В объявлении дженерик-параметра класса или метода может быть указана его верхняя граница (bound)
class Foo<T extends Number>Ключевое слово extends применяется как для классов, так и для интерфейсов. Фактическим параметром такого класса Foo может быть или сам Number, или его наследники.
Помимо ограничения возможных применяемых типов, bounded-параметр дает право использовать в реализации методы и поля типа-ограничителя – он будет как минимум предком фактического типа. Это достигается стиранием типа-параметра до верхней границы.
Тип-параметр может иметь несколько верхних границ, то есть границу-пересечение типов: <T extends Comparable & Serializable>. Стирание произойдет до первой из границ, остальные послужат только ограничением вариантов фактического типа. Поэтому граница-класс, при наличии, должна быть указана раньше границ-интерфейсов.
При указании значения дженерик-параметра переменной может быть использован вайлдкард – символ ?. Вайлдкард значит, что мы не собираемся использовать информацию о конкретном типе, этот тип может быть любым. Это не то же самое, что не указать дженерик параметр совсем.
Для вайлдкарда также как и для объявления типа-параметра можно обозначить верхнюю границу. Но в отличие от объявления здесь нельзя использовать пересечение типов, по крайней мере пока.
Кроме того в случае вайлдкарда можно задать нижнюю границу
Foo<? super Number> foo;Означает, что мы не будем использовать информацию о конкретном типе, но будем знать что это предок класса Number. То есть или сам Number, или Object.
В объявлении класса или метода использование super запрещено, так как не имеет смысла.
Разобраться в использования ограниченных вайлдкардов поможет это видео.
Хороший API должен уметь эффективно работать с классами-наследниками, то есть быть ко- или контравариантным где это необходимо. При этом без bounded вайлдкардов не обойтись. Чтобы запомнить, какая граница нужна в каких случаях, Joshua Bloch предложил мнемонику PECS: Producer-extends, Consumer-super
👍16❤1
Что произойдет при выполнении такого кода?
Anonymous Quiz
32%
Ошибка компиляции в 4-й строке
19%
Ошибка компиляции в 5-й строке
9%
Ошибка компиляции в 6-й строке
10%
Ошибка компиляции в 7-й строке
23%
Будет выведено на консоль: [1.5][1.5]
6%
Ошибка выполнения
👍19🤔6❤3🥱1
Что такое ковариантность и контравариантность?
Формально, ковариантность/контравариантность типов – это сохранение/обращение порядка наследования для производных типов. Проще говоря, когда у ковариантных сущностей типами-параметрами являются родитель и наследник, они сами становятся как бы родителем и наследником. Контравариантные наоборот, становятся наследником и родителем.
Легче всего осознать эти понятия на примерах:
🔘 Ковариантность: List<Integer> можно присвоить в переменную типа List<? extends Number> (как будто он наследник List<Number>).
🔘 Контравариантность: в качестве параметра метода List<Number>#sort типа Comparator<? super Number> может быть передан Comparator<Object> (как будто он родитель Comparator<Number>)
Отношение типов «можно присвоить» – не совсем наследование, такие типы называются совместимыми (отношение «is a»).
Существует еще одно связанное понятие – инвариантность. Инвариантность – это отсутствие свойств ковариантности и контрвариантности. Дженерики без вайлдкардов инвариантны: List<Number> нельзя положить ни в переменную типа List<Double>, ни в List<Object>.
Массивы ковариантны: в переменную Object[] можно присвоить значение типа String[].
Переопределение методов начиная с Java 5 ковариантно относительно типа результата и типов исключений.
Формально, ковариантность/контравариантность типов – это сохранение/обращение порядка наследования для производных типов. Проще говоря, когда у ковариантных сущностей типами-параметрами являются родитель и наследник, они сами становятся как бы родителем и наследником. Контравариантные наоборот, становятся наследником и родителем.
Легче всего осознать эти понятия на примерах:
🔘 Ковариантность: List<Integer> можно присвоить в переменную типа List<? extends Number> (как будто он наследник List<Number>).
🔘 Контравариантность: в качестве параметра метода List<Number>#sort типа Comparator<? super Number> может быть передан Comparator<Object> (как будто он родитель Comparator<Number>)
Отношение типов «можно присвоить» – не совсем наследование, такие типы называются совместимыми (отношение «is a»).
Существует еще одно связанное понятие – инвариантность. Инвариантность – это отсутствие свойств ковариантности и контрвариантности. Дженерики без вайлдкардов инвариантны: List<Number> нельзя положить ни в переменную типа List<Double>, ни в List<Object>.
Массивы ковариантны: в переменную Object[] можно присвоить значение типа String[].
Переопределение методов начиная с Java 5 ковариантно относительно типа результата и типов исключений.
👍20🔥1
Какой будет результат?
Anonymous Quiz
13%
howl woof sniff
7%
howl howl затем ошибка
17%
howl howl sniff
12%
howl woof затем ошибка
14%
Ошибка компиляции в строке 12
37%
Ошибка компиляции в строке 13
👍20🍾4
Что такое bridge method?
В Java отсутствует ковариантность переопределенных методов по параметрам – их типы должны совпадать с типами параметров метода в родительском классе. Когда дженерик параметр конкретизируется в наследнике, методы с аргументами этого дженерик типа больше не совпадают в байткоде – в наследнике тип конкретный, а в родителе стертый до верхней границы.
Проблема решается простым и безопасным кастом. Компилятор генерирует новый метод, который совпадает по сигнатуре с родительским. В его теле параметр кастуется и вызов делегируется в пользовательский метод. Это и называется bridge методом.
Bridge method можно увидеть с помощью рефлекшна. Его имя совпадает с оригинальным методом, но параметр имеет тип, в который сотрется дженерик родителя. Этот метод будет помечен флагом synthetic, что значит, что он написан не программистом а компилятором.
Попытка написать такой же метод вручную приведет к ошибке компиляции.
В Java отсутствует ковариантность переопределенных методов по параметрам – их типы должны совпадать с типами параметров метода в родительском классе. Когда дженерик параметр конкретизируется в наследнике, методы с аргументами этого дженерик типа больше не совпадают в байткоде – в наследнике тип конкретный, а в родителе стертый до верхней границы.
Проблема решается простым и безопасным кастом. Компилятор генерирует новый метод, который совпадает по сигнатуре с родительским. В его теле параметр кастуется и вызов делегируется в пользовательский метод. Это и называется bridge методом.
Bridge method можно увидеть с помощью рефлекшна. Его имя совпадает с оригинальным методом, но параметр имеет тип, в который сотрется дженерик родителя. Этот метод будет помечен флагом synthetic, что значит, что он написан не программистом а компилятором.
Попытка написать такой же метод вручную приведет к ошибке компиляции.
👍16🔥4❤1
Каким будет результат выполнения следующего кода?
Anonymous Quiz
36%
0
44%
-1
4%
Ничего из перечисленного
15%
Ошибка компиляции
👍37
Каким будет результат выполнения следующего кода?
Anonymous Quiz
17%
Value 1
56%
Value 3
6%
Value 2
20%
Ошибка компиляции
👍19🏆3