Java Guru 🤓
13.3K subscribers
922 photos
15 videos
777 links
Канал с вопросами и задачами с собеседований!

По сотрудничеству и рекламе: @NadikaKir

Канал в перечне РКН: https://vk.cc/cJrSQZ

Мы на бирже: telega.in/channels/javatasks/card?r=lcDuijdm
Download Telegram
Какие существуют примитивы?

В Java имеется 9 возможных типов значения переменной: ссылка на объект или один из восьми примитивных типов:
🔘 byte – знаковое целое число от -2^7 до 2^7-1;
🔘 short – знаковое целое число от -2^15 до 2^15-1;
🔘 int – знаковое целое число от -2^31 до 2^31-1;
🔘 long – знаковое целое число от -2^63 до 2^63-1;
🔘 float – знаковое число с плавающей точкой 32 бита стандарта IEEE 754;
🔘 double – то же, что и float, но 64 бита;
🔘 char – 16-битный символ Unicode, от '\u0000'(0) до '\uffff'(65535);
🔘 boolean – true или false;

По умолчанию поля примитивных типов принимают нулевые значения: 0, 0L, '\u0000', false. Про особенности работы, способ хранения и специальные значения чисел с плавающей точкой стоит почитать подробнее.

Отдельная интересная тема – boxing/unboxing. Каждый примитивный тип снабжен своей ссылочной версией. Примитивное значение заворачивается и разворачивается из него автоматически при необходимости. Это может приводить к большим затратам на выделение памяти, когда например int индекс цикла используется в качестве значения переменной Object и превращается в Integer без нужды – частая задача на собеседованиях. Еще классы-обертки содержат набор утилитарных методов для их примитивов.

Сколько памяти занимает примитив – вопрос с подвохом. Спецификация требует, чтобы размер был достаточным для всех значений. Конкретный размер определяется реализацией JVM, он может быть больше. Например в 64-bit HotSpot переменная boolean занимает не 1 бит, а 8.
👍14🔥1
⚡️Ваши программы страдают от утечек памяти и медленной работы из-за традиционной сборки мусора?

А теперь представьте, что ваши программы работают быстрее и эффективнее. Вы освоили правила владения и заимствования в Rust, научились безопасно использовать ссылки и управлять временем жизни объектов.

Ваш код стал более надежным и производительным!

🧑‍💻Присоединяйтесь к открытому вебинару «Как Rust управляет ресурсами без сборки мусора?» 1 августа в 20:00 мск и сделайте этот прыжок в будущее!

🎯 Мы рассмотрим правила владения и заимствования, посмотрим примеры кода и разберёмся, зачем в язык добавили явные лайфтаймы.

🧑‍💻Урок будет полезен разработчикам, которые хотят познакомиться с Rust или углубить свои знания об управлении ресурсами в этом языке. Вебинар подходит как для новичков, так и для опытных разработчиков.

Спикер Кирилл Федченко — опытный разработчик на нескольких языках.

👉Регистрируйтесь прямо сейчас, чтобы не пропустить мероприятие: https://vk.cc/cyM00r
👍8👏31🔥1😁1
🚀 Заканчивается набор на открытый урок "Java Generics для автоматизации тестирования"! 🚀

Стартуем 30 июля в 20:00 по мск.  Успейте попасть в группу! 

Присоединяйтесь к нашему открытому уроку по Java Generics от OTUS, ведущего образовательного центра с более чем 130 авторскими курсами для IT-специалистов. 

Открытый урок проходит в рамках курса Java QA Engineer. Professional. Для разработчиков автоматизированного тестирования на Java. Прокачайте профессиональные навыки, углубите и систематизируйте знания, научитесь грамотно внедрять автоматизацию в проекты.

👉 Что Вы узнаете на уроке?

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

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

Использование Java Generics в API автоматизации тестирования
Вы освоите методы использования Java Generics в API автоматизации тестирования. Поймете, как применять Generics для создания универсальных и мощных тестов для API, что повысит надежность и масштабируемость ваших тестовых сценариев.

🤔 Как Вы сможете применить полученные знания?

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

Создать гибкие и переиспользуемые тесты для UI
Вы научитесь применять Java Generics для создания гибких и переиспользуемых тестов для пользовательского интерфейса. Это упростит поддержку и расширение автоматизации тестирования, делая ваши тесты более надежными.

Разработать универсальны тесты для API
Вы сможете создавать универсальные и мощные тесты для API, используя Java Generics. Это повысит надежность ваших тестов и упростит их масштабирование, что важно для эффективного тестирования сложных систем.

Для регистрации на открытый урок нажмите здесь.

Торопитесь! Места ограничены.

Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.
👍41🔥1
Что такое static?

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

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

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

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

Статический импорт (static import) импортирует статические члены классов в .java-файл.
👍8🔥3
В чем разница между разными модификаторами доступа?

🔘 private – доступ только непосредственно из этого класса и его внутренних/вложенных классов;
🔘 package-private – доступ из всех классов этого пакета. Наследники доступа не имеют. Применяется когда модификатор не указан;
🔘 protected – доступ из всех классов этого пакета и всех наследников;
🔘 public – никаких ограничений доступа;

Модификаторы доступа применяются к классам, интерфейсам, методам и полям. Они нужны для реализации принципа наименьших привилегий и для отделения внутренней реализации от частей публичного API.
👍11🔥1
🔄 Как часто вам приходится вносить изменения в тесты из-за обновления интерфейса? 

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

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

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

🔧Ваши тесты API часто оказываются негибкими и требуют множества изменений при добавлении новых эндпоинтов? 

Применение Java Generics для создания универсальных тестов помогает создать тесты, которые могут адаптироваться под различные эндпоинты. 

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

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

🔍Приходится ли вам сталкиваться с повторяющимися структурами данных в тестах? 

Это может усложнять их поддержку и читабельность. С помощью Java Generics можно создать общие классы и методы для обработки различных типов данных, что сделает ваш код более организованным и понятным. 

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

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

🌐Сложности с поддержкой тестов на разные типы браузеров? 

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

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

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

📢Хотите узнать как применить Java Generics на своих проектах?

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

Открытый урок проходит в рамках курса Java QA Engineer. Professional. Для разработчиков автоматизированного тестирования на Java.

🗓Стартуем сегодня в 20:00 по мск.

Торопитесь! Места ограничены. Для регистрации на открытый урок нажмите здесь.

Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.
👍4🔥2
Опишите процесс создания экземпляра класса

Сначала класс и цепочка его предков должны быть загружены, сверху вниз. Рассмотрим ClassLoader и процесс загрузки классов в будущих постах. Здесь важно сказать, что класс загружается только один раз, при первом к нему обращении в рамках одного класслоадера.

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

Далее инстанциируется сам экземпляр. Как и с загрузкой классов, процесс выполняется для всей цепочки наследования, с самого дальнего родителя:
1. Выделяется память в куче для экземпляра, получается ссылка на этот экземпляр;
2. Выполняются инициализации нестатических полей и блоков инициализации в порядке объявления;
3. Вызывается конструктор;

Статические поля интерфейсов не инициализируются при создании объекта, а другого состояния интерфейс не имеет – это исключает вопрос порядка инициализации предков при множественном наследовании.

В процессе конструирования объекта может возникать проблема виртуального вызова в конструкторе, свойственная для многих языков.
Effective Java Item 17 рекомендует не использовать переопределяемые методы в расширяемом классе. Иллюстрация неочевидного поведения в результате приведена выше на картинке
👍103🔥2❤‍🔥1
📚 Пройди тест на знание Java и получи доступ к 59 открытым урокам по Spring

🕗 Два открытых урока можно посмотреть без регистрации и оценить формат обучения. Для доступа ко всем открытым урокам из курса «Разработчик на Spring Framework» от OTUS необходимо пройти входное тестирование: ответить на 21 вопрос и уложиться в тайминг.

📊 -Курс рассчитан на профессионалов с практическим опытом работы на Java.
- Мы будем 5 месяцев погружать вас в теорию и практику Spring Framework.
- Дадим 18 практических работ. Процесс review сдаваемой работы максимально приближен к тому, каким он мог быть на реальном проекте. Помимо этого, мы попросим вас сдать дипломную работу, каких скучных записанных занятий, только живые онлайн-лекции, интересные практические задачи и развернутая обратная связь от лучших экспертов ниши. 📅 Старт группы уже 31 июля 2024г. Доступна рассрочка на обучение.

➡️ НАЧАТЬ ТЕСТИРОВАНИЕ

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
👍3🔥2
new Integer(128) == 128?

Для всех классов-оберток над примитивами кроме Float и Double работает механизм кэширования. Некоторые значения создаются на этапе инициализации класса, и переиспользуются когда объект создается не оператором new (например с помощью valueOf).

Кэшируемые значения – оба возможных Boolean, Character до '\u007f' (127) и все целые числа от -128 до 127 включительно. С Java 7 верхнюю границу для Integer можно увеличить параметром java.lang.Integer.IntegerCache.high.

Значения кэшируются и во многих других встроенных классах: BigDecimal, Currency, пустые коллекции. Детали можно узнавать из исходников и документаций, так как эти кэши реализованы не на уровне JVM а в коде классов.

В конкретно этом примере скрыт еще один подвох: объект класса-обертки сравнивается с примитивом. Это приводит к анбоксингу и сравнению значений. И ответ на вопрос – да.
🔥13👍53
Что можно делать с переменной хранящей null?

Во-первых, если переменная не финальная, использовать как L-value этого типа – присваивать новое значение.

Во-вторых, то же, что со значением null, но с учетом типа:
🔘 Сравнивать с null или переменной этого же класса;
🔘 Приводить к типу-родителю (upcast) или типу-наследнику (downcast), учитывая границы generic-параметров при наличии;
🔘 Обращаться к членам экземпляра и получать NullPointerException;
🔘 Применять instanceof и получать false
🔘 Использовать как параметр для методов и других совместимых с типом операторов

В-третьих, можно обращаться к статическим членам класса. В вопросе подразумевается именно эта интересная часть. Это безопасно, NullPointerException не возникнет, но для упрощения отладки и из-за отсутствия переопределения статических членов рекомендуется так не делать. Вместо этого обращайтесь к статике явно через имя класса, либо неявно, добавив для класса import static.
👍12🔥31
Что такое enum?

enum
– тип-перечисление. Бывает много разных формулировок вопроса, все они сводятся к разговору о перечислениях вообще. Технически это финальный класс со статическими финальными полями-экземплярами. enum Foo всегда неявно наследуется от Enum<Foo> – то есть перечислением нельзя расширить другой класс, но всё еще можно реализовать интерфейсы. Из-за generic-параметра разные перечисления не имеют общего предка кроме Object.

Является Comparable (сравнивается позиция по порядку объявления значений) и Serializable (сериализуется только имя константы).

Имеет только заранее заданный набор значений. Значения неявно public static final и это нельзя переопределить. Для инициализации констант действуют все правила статической инициализации.

Копии элементов перечисления не создаются даже при десериализации. Вот почему Effective Java предлагает использовать для сериализуемого синглтона enum.

Экземпляры хранят свойства name и ordinal – имя и порядковый номер константы. Статический метод values вернет список всех констант, valueOf – константу по имени.
Спецификация.

Финализация и клонирование перечислений запрещены.
👍11🔥3
👩‍💻 Что такое Reflection API и как с этим работать?

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

Встречаемся 7 августа в 20:00 мск.

Спикер Александр Фисунов — Senior Kotlin Developer в SSP Software на проекте ВТБ, опытный Java-разработчик и кандидат технических наук.

👉 Регистрируйтесь прямо сейчас, чтобы не пропустить мероприятие: https://vk.cc/cyTeXM

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥42👍2
Зачем нужен загрузчик классов?

В Java используется динамическая загрузка классов. Ее выполняют загрузчики – наследники абстрактного класса ClassLoader. Кроме того, они же загружают и файлы-ресурсы.

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

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

В URLClassLoader и стандартных загрузчиках JVM источником класса служит .class-файл. Другие загрузчики в своей реализации используют и другие источники: это может быть сетевой ресурс, или класс может генерироваться в рантайме. К примеру загрузчик из javassist специализируется на создании классов на лету.

В результате загрузки создается экземпляр класса Class. В отличие от обычных объектов, такие экземпляры хранятся не в куче, а в permgen/metaspace. Class может быть выгружен, когда загрузивший его ClassLoader стал мусором.
👍124🔥3
Тестовое собеседование на Middle Java-разработчика в эту среду

7 августа в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.

Как это будет:
1. Степан Аракелян, ex-Tech Lead в МТС и ментор в ШОРКТАТ, проведет настоящее собеседование на Middle Java-разработчика
2. Степан будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
3. В конце можно будет задать любой вопрос Степану

На открытом эфире ШОРТКАТ ты узнаешь:
- Чего ждут от кандидатов на Middle позиции в Java-разработке
- Какие вопросы задают на интервью и зачем
- Как подготовиться к собесу, чтобы получить оффер

Это бесплатно?
Бесплатно

Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
🎉7👍4🔥2
Какие существуют стандартные загрузчики классов?

В JVM встроено как минимум три стандартных загрузчика:

🔘 Bootstrap – встроенная в JVM нативная реализация, родитель для всех остальных загрузчиков. Загружает часть стандартных классов java.*;
🔘 Platform – отвечает за загрузку стандартных классов Java-рантайма. До Java 9 назывался Extension и занимался загрузкой расширений. Гарантируется, что ему будут видны (но не факт что загружены непосредственно им) все стандартные классы Java SE и JDK;
🔘 System (Application) – загружает классы из classpath конкретного приложения;

Перед тем как загрузить класс, ClassLoader проверит, не может ли это сделать его родитель. Если класс уже загружен, то загрузка не потребуется.

Иллюстрация смысла этой иерархии – загрузчики web-сервера Apache Tomcat. Прикладной код каждого web-приложения работает на своем отдельном загрузчике изолированно от других приложений. Даже один и тот же класс-singleton у каждого приложения будет собственный. Системные классы и общие библиотеки при том грузятся их родительскими загрузчиками, только один раз для сервера.
👏11👍6
Офер в Яндекс для опытных бэкендеров за два дня

24–25 августа приглашаем бэкендеров с опытом работы от пяти лет получить офер в Яндекс через multitrack за 2 дня. Достаточно решить задачи онлайн до 20 августа и пройти несколько технических секции 24 августа, чтобы уже 25-го получить офер и выбрать три команды, к которым вам было бы интересно присоединиться.

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

Узнать подробности и зарегистрироваться.

Реклама. ООО "Яндекс". ИНН 7736207543
🔥42👍2😁1
Чем отличается перегрузка от переопределения?

Полиморфизм – соль ООП. Перегрузка (overload) и переопределение (override) – два инструмента достижения полиморфного поведения в Java.

Перегрузкой реализуется ad-hoc-полиморфизм. Это значит «один и тот же» метод может работать с разными параметрами. С технической точки зрения это просто два разных метода, сигнатуры которых имеют одинаковое название, но разный набор параметров. Важно помнить, что для перегрузки не достаточно различий только модификаторов, возвращаемых типов и списков исключений.

Ad-hoc – не совсем настоящий полиморфизм, так как при нём используется раннее, или статическое связывание (early binding, static dispatch). Это значит, что для выбора конкретного варианта метода используется информация о типе переменной, а не объекта в ней лежащего, и происходит это еще при компиляции.

Если в классе объявлены два перегруженных метода, а аргумент в вызове подходит под оба, случится ошибка компиляции. В примере выше компилятор не может выбрать между вариантами метода println с параметром char[] и со String, так как null может быть и тем и другим.

Переопределение (override) дает полиморфизм подтипов. Это реализация/подмена метода нефинального родительского класса или интерфейса. С помощью этого механизма достигается поведение, когда экземпляр хранится под типом родителя, но реализация методов используется специфичная для этого конкретного подтипа. Пример:
List<String> list = new LinkedList<>();
list.add(“foo“);


Здесь метод add вызывается общий для всех списков, но добавлен будет именно элемент связного списка.

Выбор конкретного метода происходит в последний момент, в процессе работы программы, в зависимости от типа объекта. Это называется позднее или динамическое связывание методов (late binding, dynamic dispatch).

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

Переопределенный метод принято снабжать аннотацией
@Override. Ее отсутствие допускается, но компиляция не перегружающего метода с такой аннотацией приведет к ошибке.

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

Статические методы нельзя переопределить, можно только перегрузить.
👍13🔥122
⚡️ Узнайте, как манипулировать байт кодом Java-приложений!

На открытом уроке курса «Java Developer. Advanced» разберем, как просматривать и читать байт код классов и для чего это может быть нужно. Научитесь создавать утилиты для изменения байт кода существующих классов в runtime. Это знание поможет вам улучшить производительность ваших приложений и решать сложные задачи.

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

Встречаемся 7 августа в 20:00 мск.

Спикер — Tech Lead в одном из крупнейших российских банков и кандидат технических наук.

👉 Регистрируйтесь прямо сейчас, чтобы посетить бесплатное занятие: https://vk.cc/cz2snD

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
🥰4👍2🔥2
Как написать синглтон?

Singleton – это паттерн проектирования «одиночка», класс с единственным экземпляром. Такая пространная формулировка открывает простор для подходов к реализации, а значит и для уточняющих вопросов, на которые и рассчитывает интервьюер.

Первое что надо выяснить – единственный экземпляр в рамках чего. В базовом случае уникальность объекта обеспечивается на уровне реализации класса. Но при этом базовом подходе создается по объекту на каждый класслоадер. Для уникальности на всю виртуальную машину реализацию нужно дополнить. Понадобится больше действий уже на уровне ОС чтобы добиться единого экземпляра между процессами JVM. С другой стороны, может требоваться специфичное для фреймворка сужение «области уникальности», например по экземпляру на каждый Spring IoC-контейнер.

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

И наконец нужно уточнить, в каких обстоятельствах подразумевается его использовать. Обычно предлагают условие многопоточной среды – инстанцирование необходимо синхронизировать. Другое возможное требование – сохранение состояния от запуска к запуску. Спектр опций здесь ограничивается только фантазией собеседующего.
👍12🔥5
📚 Пройди тест на знание Java и получи доступ к 7️⃣2️⃣ открытым урокам по Java

Два открытых урока можно посмотреть без регистрации и оценить формат обучения. Для доступа ко всем открытым урокам из курса «Java Developer. Professional» от OTUS необходимо пройти входное тестирование: ответить на 20 вопросов и уложиться в тайминг.

📊 -Курс рассчитан на профессионалов с практическим опытом работы на Java.
На курсе вы освоите:
- создание современных Java-приложений;
- основы функционирования JVM (сборка мусора, byteCode);
- приемы применения многопоточности;
- решение задач уровня Middle+;
- современные фреймворки Spring WebFlux, Kafka, реактивный Postgres и Kubernetes;
- написание кода чище и быстрее.

Забудьте о скучном обучении — здесь вас ждут настоящие челленджи и нестандартные практические решения. А еще сильные проекты для портфолио и карьерный сапорт! 📅 Старт группы уже 29 августа 2024г. Доступна рассрочка на обучение.

➡️ НАЧАТЬ ТЕСТИРОВАНИЕ

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52🥰2🔥1
Чем отличается interface от @⁠interface?

Среди интерфейсов выделяется особая группа, которая не объявляет никаких методов. Пример такого интерфейса – Serializable. Такие интерфейсы добавляют классу некую семантику, которая позже используется либо с помощью рефлексии (и instanceof), либо вообще не программно, а как информация для разработчиков и инструментов разработки. Это маркерные интерфейсы. Маркерный интерфейс представляет метаинформацию класса.

Начиная с Java 1.5 в языке появился новый вид типов – аннотации. Они берут на себя и расширяют возможности маркерного интерфейса:
1. Можно применять аннотацию не только к классу или интерфейсу, но почти к чему угодно: к пакетам, к методам, их параметрам, переменным. Полный список представлен в перечислении ElementType;
2. Аннотация может нести данные в своих элементах
3. Аннотация может не присутствовать в рантайме, или даже остаться только в исходнике, не попав в байткод вовсе. Определяется ее RetentionPolicy;
4. Можно сделать аннотацию не наследуемой, просто не помечая ее
@Inherited;
5. И конечно же, синтаксис. Примененная аннотация с первого взгляда отличается от настоящих интерфейсов.

Joshua Block в главе 37 Effective Java выделяет два преимущества маркерных интерфейсов перед аннотациями на этапе компиляции:
1. Можно требовать использование только маркированного параметра, так как маркерный интерфейс – это еще и тип;
2. Можно сузить применяемость маркера к только определенным типам, сделав интерфейс их наследником.

Возвращаясь к вопросу, ключевое слово
@interface объявляет аннотацию, interface – интерфейс.

В результате компиляции в .class-файле аннотация превращается в интерфейс-наследник java.lang.annotation.Annotation, помеченный флагом ACC_ANNOTATION. Элементы превращаются в абстрактные методы. Этим объясняется синтаксис объявления. Специфичные для аннотаций атрибуты описаны в JVMS 4.7.16-4.7.22.

К слову, конструкции вида
@something в javadoc называются тэгами. Они выглядят похоже на аннотации, также представляют метаинформацию для документации, но технически не имеют с ними ничего общего.
👍10🔥4🎉32