JavaRush /Java блог /Random /Кофе-брейк #282. Создание пользовательской аннотации в Ja...

Кофе-брейк #282. Создание пользовательской аннотации в Java. Дженерики и стирание типов в Java

Статья из группы Random

Создание пользовательской аннотации в Java

Источник: Medium Благодаря этой публикации вы узнаете, как создавать три типа пользовательских аннотаций, и как можно использовать эти аннотации для улучшения своих программ. Кофе-брейк #282. Создание пользовательской аннотации в Java. Дженерики и стирание типов в Java - 1

Что такое аннотации в Java?

Аннотация — это функция, которая служит механизмом добавления в код дополнительной информации, что способствует улучшению организации, документирования и автоматизации в рамках программных проектов. Если вы какое-то время программировали на Java, то, вероятно, вам знакома хотя бы пара аннотаций. Одним из примеров является @Override. Хотя аннотации используют многие разработчики, не все из них понимают, насколько легко создавать собственные аннотации. При этом многие платформы часто используют свои собственные аннотации наряду со встроенными аннотациями Java.

Как создать пользовательскую аннотацию

Процесс создания аннотаций в Java довольно прост. Для объявления аннотации используется ключевое слово @interface.

//@Retention(...) 
//@Target(...) 
public @interface CustomAnnotation{
//    ...
}
Технически, ключевое слово @interface — это все, что вам нужно для создания пользовательских аннотаций. Однако, прежде чем вы сможете эффективно использовать свои собственные аннотации, вам нужно выполнить настройку в соответствии с вашими конкретными потребностями. В этом помогут так называемые мета-аннотации, а именно @Target, @Retention, @Inherited и @Documented. Их можно использовать только для аннотирования других аннотаций. Две из них являются основными аннотациями, на которых мы сосредоточимся. @Target() — эта аннотация описывает, где вы можете применить свою собственную аннотацию. Он принимает перечисление ElementType в качестве единственного аргумента, но можно его и не указывать. Поскольку мы хотим, чтобы аннотация была действительна только для классов, мы будем использовать TYPE. Кроме того, мы можем передать несколько ElementTypes, например @Target({ElementType.TYPE, ElementType.METHOD}). Кофе-брейк #282. Создание пользовательской аннотации в Java. Дженерики и стирание типов в Java - 2@Retention() — эта аннотация используется для определения того, на каком уровне аннотация будет храниться с помощью политик хранения. В 99% случаев мы используем RetentionPolicy.RUNTIME. Это сохраняет аннотацию доступной на протяжении всего фактического выполнения программы. Кофе-брейк #282. Создание пользовательской аннотации в Java. Дженерики и стирание типов в Java - 3

Три типа пользовательских аннотаций

Мы можем разделить типы аннотаций на три основных заголовка: аннотация маркера (Marker Annotation), аннотация с одним значением (Single Value Annotation) и аннотация с несколькими значениями (Multi Value Annotation). 1. Marker Annotation не имеет методов. Они используются для указания того, что сущность имеет определенное качество или представляет определенное состояние. Давайте создадим пример аннотации под названием @Unrepaired, которая используется для обозначения электронных устройств, не прошедших ремонт:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)// только для полей
public @interface Unrepaired{
 }

@Important
public class Electronics {

    @Unrepaired
    private List<String> smartPhones; // Смартфон не ремонтировался.

    private List<String> laptops;

    private List<String> tablets;
}

public static void main(String[] args) {

        Electronics electronics = new Electronics()
       
     for(Field field: electronics.getClass().getDeclaredFields()){
           if(field.isAnnotationPresent(Unrepaired.class)){
               Unrepaired unrepaired = field.getAnnotation(Unrepaired.class);
               System.out.println("Field: " + field.getName() + " has not been repaired.");
           }
       }
    }
// Вывод: Field: smartPhones has not been repaired.
2. Single Value Annotation содержит только один метод. Этот метод обычно представляет значение, связанное с аннотацией. Например, мы можем создать аннотацию с одним значением с именем @Discount, чтобы применять скидки к определенным категориям одежды.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)// только для метода
public @interface Discount {
    double value(); // здесь необычно, технически мы должны сделать это методом, 
      // а не обычным полем класса, поэтому для этого нам нужно добавить круглые скобки.
}
// если мы хотим указать значение по умолчанию -> double value() default 0.0;

public class Clothing {

    @Discount(0.2) // скидка доступна только для метода tshirt.
    public void tshirt() {
        System.out.println("Discount is applied");
    }  

    public void dress() {
        System.out.println("There is no discount");
    }
}

public static void main(String[] args) {

        Clothing clothing = new Clothing();

       for(Method method : clothing.getClass().getDeclaredMethods()){
           if(method.isAnnotationPresent(Discount.class)){
               Discount discount = method.getAnnotation(Discount.class);
               System.out.println("Method: " + method.getName() + " has a discount of " + discount.value());
           }
       }
    }
// Вывод: Method: tshirt has a discount of 0.2
3. Multi Value Annotation имеет несколько элементов и обычно используется для указания различных свойств. Например, давайте создадим аннотацию @Restriction, которую можно использовать для управления частотой вызова метода.

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) // только для метода 
public  @interface Restriction { 
    int  minFrequency ()  default  1 ; // Минимальная частота вызова метода 
    int  maxFrequency ()  default Integer.MAX_VALUE; // Максимальная частота вызова метода
 }
Элементы minFrequency и maxFrequency используются для указания того, сколько раз можно вызывать метод. К примеру, в приложении электронной коммерции мы могли бы использовать эту аннотацию для управления частотой добавления товара в корзину в определенном диапазоне. Аннотации — это важнейшая функция, которая позволяет нам эффективно организовывать, документировать и автоматизировать наш код. Создание пользовательских аннотаций не только повышает читаемость и удобство обслуживания нашего кода, но также помогает сделать наши программные проекты более эффективными. Я надеюсь, что эта статья послужит ценным руководством на вашем пути разработки Java. Приятного кодирования!

Дженерики и стирание типов в Java

Источник: Asyncq Используя это учебное руководство, вы сможете представить работу дженериков и стирание типов на простом примере кода Java.

Введение

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

Дженерики в Java

  • Дженерики (Generics) были представлены в Java 5, их основная цель заключалась в обеспечении проверок безопасности типов во время компиляции, а также гибкости и возможности повторного использования кода.
  • Одной из областей, где дженерики сыграли значительную роль, была структура коллекций. До появления дженериков Java Collection использовалась с типом RAW. Использование типа Raw было подвержено ошибкам, и разработчики часто выполняли приведение типов данных, что приводило к исключениям при приведении типов.
  • Используя Generics, разработчики будут определять тип данных, которые им необходимо хранить в коллекции, и любое нарушение будет являться ошибкой времени компиляции.
Кофе-брейк #282. Создание пользовательской аннотации в Java. Дженерики и стирание типов в Java - 4

Стирание типов (Type Erasure)

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

Пример кода

Давайте рассмотрим простой пример. Мы создаем GenericContainer, у которого есть конструктор и метод добавления. GenericContainer принимает параметр типа T, который передается этому классу из клиентского кода во время инициализации.

GenericContainer<String> gc = new GenericContainer<>();

public class GenericContainer<T> {
 
    int initialCapacity = 100;
    Object[] elementArray = null;
    T t;
 
    public GenericContainer() {
        elementArray = new Object[initialCapacity];
    }
 
    public void add(T t){
        this.t = t;
       // добавить элемент
    }
}
  • Если мы скомпилируем этот файл, мы увидим, что параметр типа стерт и использован родительский класс Object.

javac ./src/main/java/Generics/GenericContainer.java
// GenericContainer.class
  • Теперь мы можем использовать инструмент javap для проверки файла GenericContainer.class.

javap -c ./src/main/java/Generics/GenericContainer.class
Кофе-брейк #282. Создание пользовательской аннотации в Java. Дженерики и стирание типов в Java - 5
  • Как мы видим, putfield передает тип объекта и не хранит общие параметры.
В этой статье мы обсудили дженерики и стирание типов. Мы также видели простой пример кода, подтверждающий это.
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ