Получается, что аннотация java — это просто пометка, и у нее нет никаких возможностей.

Java задняя часть
Получается, что аннотация java — это просто пометка, и у нее нет никаких возможностей.

镇楼


предисловие

В java есть волшебное существование. В аннотации тот парень, который @другие каждый день. Где это святое?

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


что такое аннотации

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


встроенные аннотации

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

А эта отметка и есть аннотация. В JDK есть несколько встроенных аннотаций, таких как @Override. Все они находятся в пакете java.lang. Давайте рассмотрим их отдельно.

@Override

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

在这里插入图片描述

Сначала я не знал, что это такое, пока однажды я не удалил этот метод в интерфейсе, и компиляция не удалась.

在这里插入图片描述

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

在这里插入图片描述

@Deprecated

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

在这里插入图片描述

@SuppressWarnings

Подавить предупреждения.

package com.secondgod.annotation;

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        List          objList = intList;
        objList.add("二当家的");
    }
}

Включите компиляцию предлагаемых предупреждений в командной строке (команды имеют вид javac -d . -Xlint Test.java , а компиляция включения предлагаемых предупреждений будет упомянута позже, и объяснение повторяться не будет).

在这里插入图片描述

С небольшой модификацией кода предупреждение компиляции можно убрать.

package com.secondgod.annotation;

import java.util.ArrayList;
import java.util.List;

public class Test {

    @SuppressWarnings({"unchecked", "rawtypes"})
    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        List          objList = intList;
        objList.add("二当家的");
    }
}

@SafeVarargs

Компилятор Java выдает непроверенное предупреждение при объявлении вариативного конструктора или метода неоднозначного типа (например, универсального). Учитывая эти обстоятельства, если программист приходит к выводу, что тела объявленных конструкторов и методов не будут выполнять потенциально небезопасные операции со своими параметрами varargs, они могут быть помечены @SafeVarargs, чтобы компилятор Java не выдавал непроверенное предупреждение.

package com.secondgod.annotation;

import java.util.List;

public class Test {
    public final void test(List<String>... stringLists) {

    }
}

Включить компиляцию с предупреждениями в командной строке.

在这里插入图片描述

С небольшой модификацией кода предупреждение компиляции можно убрать.

package com.secondgod.annotation;

import java.util.List;

public class Test {
    @SafeVarargs
    public final void test(List<String>... stringLists) {

    }
}

@FunctionalInterface

Аннотации функционального интерфейса, новая функция, представленная в Java 1.8. Функциональное программирование сейчас в моде, поэтому Java 8 добавила эту возможность как раз вовремя. Какая польза от этой аннотации? Эта аннотация гарантирует, что этот интерфейс имеет только один абстрактный метод, обратите внимание, что он может изменять только интерфейс.

  1. интерфейс без абстрактных методов
package com.secondgod.annotation;

@FunctionalInterface
public interface Test {
    
}

在这里插入图片描述

  1. Интерфейс с более чем одним абстрактным методом
package com.secondgod.annotation;

@FunctionalInterface
public interface Test {
    String test1();

    String test2();
}

在这里插入图片描述

  1. Интерфейс только с одним абстрактным методом

Скомпилирован.

package com.secondgod.annotation;

@FunctionalInterface
public interface Test {
    String test();
}
  1. Только абстрактный класс абстрактного метода
package com.secondgod.annotation;

@FunctionalInterface
public abstract class Test {
    public abstract String test();
}

在这里插入图片描述


метааннотация

Когда мы откроем исходный код @Override и посмотрим на него, мы обнаружим, что есть аннотации на определение этой аннотации, то есть аннотации аннотаций, люди обычно называют их мета-аннотациями. Мета-аннотации — это аннотации, отвечающие за объяснение других аннотаций. Мета-аннотации можно использовать при настройке аннотаций.

在这里插入图片描述

Все встроенные метааннотации JDK находятся в пакете java.lang.annotation.

在这里插入图片描述

@Target

Target означает цель, а @Target указывает, где применяется аннотация.

стоимость Примечание
TYPE Может использоваться на классе или интерфейсе
FIELD Доступно для полей/полей/свойств
METHOD можно использовать метод
PARAMETER можно использовать в параметрах
CONSTRUCTOR Можно использовать в конструкторе
LOCAL_VARIABLE можно использовать с локальными переменными
ANNOTATION_TYPE Может использоваться для аннотированных типов (типы, измененные @interface)
PACKAGE Используется для записи информации о пакете файлов Java.
TYPE_PARAMETER Может использоваться в объявлениях переменных типа
TYPE_USE Может использоваться в любом операторе, использующем тип

@Documented

Аннотированные классы, украшенные аннотацией @Documented, будут извлечены в документацию инструментом JavaDoc. По умолчанию JavaDoc не включает аннотации, но если при объявлении аннотации указано @Documented, она будет обработана такими инструментами, как JavaDoc, поэтому информация о типе аннотации будет включена в сгенерированную справочную документацию.

@Inherited

Унаследованное означает наследование, но это не означает, что сама аннотация может быть унаследована, но что если суперкласс аннотирован аннотацией @Inherited, то если его подкласс не применяется ни одной аннотацией, то подкласс Класс наследует аннотации суперкласс.

@Repeatable

Повторяемый естественно означает повторяемый. Недавно добавленный в Java 8, он позволяет повторять аннотации в одном и том же программном элементе.Когда вам нужно использовать одну и ту же аннотацию несколько раз, вам часто нужно использовать аннотацию @Repeatable. До Java 8 перед одним и тем же элементом программы могла быть только одна аннотация одного типа.Если вам нужно использовать несколько аннотаций одного типа перед одним и тем же элементом, вы должны использовать аннотацию «контейнер». .

@Retention

@Retention используется для описания жизненного цикла аннотации, то есть того, как долго аннотация сохраняется. Переменная-член (значение) в аннотации @Retention используется для установки политики хранения. Значение представляет собой тип перечисления java.lang.annotation.RetentionPolicy. RetentionPolicy имеет 3 константы перечисления, как показано ниже.

стоимость Жизненный цикл
SOURCE Действителен в исходных файлах (может использоваться компилятором)
CLASS Действителен в файлах классов (может использоваться компиляторами и виртуальными машинами)
RUNTIME Действителен во время выполнения (могут использоваться компилятор, виртуальная машина, среда выполнения программы)

@Native

Использование аннотации @Native для изменения переменной-члена означает, что на эту переменную может ссылаться собственный код, и она часто используется средствами генерации кода. Он также находится в пакете java.lang.annotation, но я не думаю, что это мета-аннотация, потому что он не предназначен для аннотаций.

在这里插入图片描述


пользовательская аннотация

Аннотации есть в Spring, Hibernate, Mybatis и других фреймворках.Второй мастер тоже пытается настроить аннотацию.Давайте посмотрим на исходный код @Override.

package java.lang;

import java.lang.annotation.*;

/**
 * Indicates that a method declaration is intended to override a
 * method declaration in a supertype. If a method is annotated with
 * this annotation type compilers are required to generate an error
 * message unless at least one of the following conditions hold:
 *
 * <ul><li>
 * The method does override or implement a method declared in a
 * supertype.
 * </li><li>
 * The method has a signature that is override-equivalent to that of
 * any public method declared in {@linkplain Object}.
 * </li></ul>
 *
 * @author  Peter von der Ah&eacute;
 * @author  Joshua Bloch
 * @jls 9.6.1.4 @Override
 * @since 1.5
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

Мы также настраиваем один в соответствии с рисунком тыквы.

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 测试注解
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}

Наши пользовательские аннотации обычно определяют жизненный цикл как RUNTIME. Жизненный цикл SOURCE требует сотрудничества с компилятором. Жизненный цикл КЛАСС и требует сотрудничества виртуальной машины. Мы можем настроить только поведение программы во время выполнения.

Хорошо, давайте воспользуемся этой пользовательской аннотацией.

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * 测试注解
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
}

/**
 * 对自定义注解的测试
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
public class Test {
    @MyAnnotation
    private String name;
}

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

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * 测试注解
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String name();
}

/**
 * 对自定义注解的测试
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
public class Test {
    @MyAnnotation(name = "二当家的")
    private String name;
}

При его использовании вы должны указать имя атрибута для назначения. В некоторых аннотациях, таких как @Target, не нужно писать имя атрибута при присвоении значения. Это потому, что имя атрибута является «значением», поэтому вам не нужно Напиши это.

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * 测试注解
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String value();
}

/**
 * 对自定义注解的测试
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
public class Test {
    @MyAnnotation("二当家的")
    private String name;
}

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

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * 测试注解
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String value() default "二当家的";
}

/**
 * 对自定义注解的测试
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
public class Test {
    @MyAnnotation
    private String name;
}

Контента в аннотации очень мало, явно его функция в ней не реализована. Таким образом, аннотация — это всего лишь разметка, которая сама по себе не имеет никакой функции. Итак, как это работает?


Аннотация в действии

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

package com.secondgod.annotation;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 工具类
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
public class MyUtils {
    /**
     * 私有构造,不可实例化
     */
    private MyUtils() {}

    /**
     * 用于对属性按照环境变量默认初始化
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface EnvironmentVariables {
        /**
         * 环境变量的key
         * @return
         */
        String value();
    }

    /**
     * 取得类实例,并用环境变量初始化
     *
     * @param clazz
     * @param <T>
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws java.beans.IntrospectionException
     * @throws InvocationTargetException
     */
    public static <T> T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException, IntrospectionException, InvocationTargetException {
        T obj = clazz.newInstance();
        setEnvironmentVariables(obj);
        return obj;
    }

    /**
     * 为对象属性按照环境变量赋值
     *
     * @param o
     * @throws IllegalAccessException
     */
    public static void setEnvironmentVariables(Object o) throws IllegalAccessException, IntrospectionException, InvocationTargetException {
        for (Field f : o.getClass().getDeclaredFields()) {
            // 利用反射读取注解
            EnvironmentVariables environmentVariables = f.getDeclaredAnnotation(EnvironmentVariables.class);
            if (environmentVariables != null) {
                // 如果注解存在就读取环境变量
                String value = System.getProperty(environmentVariables.value());
                // 利用内省将值写入
                PropertyDescriptor pd = new PropertyDescriptor(f.getName(), o.getClass());
                pd.getWriteMethod().invoke(o, value);
            }
        }
    }
}

Мы определяем класс для представления информации о виртуальной машине и аннотируем поля атрибутов аннотациями.

package com.secondgod.annotation;

import java.text.MessageFormat;

/**
 * 虚拟机信息
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
public class VmInfo {
    @MyUtils.EnvironmentVariables(value = "java.vm.version")
    private String version;
    @MyUtils.EnvironmentVariables(value = "java.vm.vendor")
    private String vendor;
    @MyUtils.EnvironmentVariables(value = "java.vm.name")
    private String name;
    @MyUtils.EnvironmentVariables(value = "java.vm.specification.name")
    private String specName;
    @MyUtils.EnvironmentVariables(value = "java.vm.specification.vendor")
    private String specVendor;
    @MyUtils.EnvironmentVariables(value = "java.vm.specification.version")
    private String specVersion;
    @MyUtils.EnvironmentVariables(value = "java.vm.info")
    private String info;

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getVendor() {
        return vendor;
    }

    public void setVendor(String vendor) {
        this.vendor = vendor;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSpecName() {
        return specName;
    }

    public void setSpecName(String specName) {
        this.specName = specName;
    }

    public String getSpecVendor() {
        return specVendor;
    }

    public void setSpecVendor(String specVendor) {
        this.specVendor = specVendor;
    }

    public String getSpecVersion() {
        return specVersion;
    }

    public void setSpecVersion(String specVersion) {
        this.specVersion = specVersion;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public String toString() {
        return MessageFormat.format("version={0},vendor={1},name={2},specName={3},specVendor={4},specVersion={5},info={6}", version, vendor, name, specName, specVendor, specVendor, info);
    }
}

Хорошо, давайте протестируем наш инструмент.

package com.secondgod.annotation;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;

/**
 * 对自定义注解的测试
 *
 * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
 */
public class Test {

    public static void main(String[] args) throws IntrospectionException, InvocationTargetException, IllegalAccessException, InstantiationException {
        VmInfo info1 = new VmInfo();
        System.out.println("普通方式实例化后:" + info1);
        VmInfo info2 = MyUtils.getInstance(VmInfo.class);
        System.out.println("使用我们的小工具实例化后:" + info2);
    }
}

在这里插入图片描述

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


конец

В Spring, Hibernate, Mybatis и других фреймворках есть пользовательские аннотации, которые часто используются в качестве еще одного параметра конфигурации в дополнение к файлам конфигурации. У них есть преимущества и недостатки, и их следует выбирать в соответствии с реальной ситуацией. Файл конфигурации можно модифицировать для перезапуска программы, а модификацию аннотации, очевидно, можно только перекомпилировать. Однако второй мастер считает, что разместить конфигурацию прямо в месте использования очень удобно, да и читабельность лучше, поэтому, если нет необходимости в пострелизной доработке, второй мастер любит использовать аннотации. Однако использование аннотаций будет более разрозненным, а не таким централизованным, как файлы конфигурации. Эй, благожелательный видит благоволение, а мудрый видит мудрость.