предисловие
В 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 добавила эту возможность как раз вовремя. Какая польза от этой аннотации? Эта аннотация гарантирует, что этот интерфейс имеет только один абстрактный метод, обратите внимание, что он может изменять только интерфейс.
- интерфейс без абстрактных методов
package com.secondgod.annotation;
@FunctionalInterface
public interface Test {
}
- Интерфейс с более чем одним абстрактным методом
package com.secondgod.annotation;
@FunctionalInterface
public interface Test {
String test1();
String test2();
}
- Интерфейс только с одним абстрактным методом
Скомпилирован.
package com.secondgod.annotation;
@FunctionalInterface
public interface Test {
String test();
}
- Только абстрактный класс абстрактного метода
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é
* @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 и других фреймворках есть пользовательские аннотации, которые часто используются в качестве еще одного параметра конфигурации в дополнение к файлам конфигурации. У них есть преимущества и недостатки, и их следует выбирать в соответствии с реальной ситуацией. Файл конфигурации можно модифицировать для перезапуска программы, а модификацию аннотации, очевидно, можно только перекомпилировать. Однако второй мастер считает, что разместить конфигурацию прямо в месте использования очень удобно, да и читабельность лучше, поэтому, если нет необходимости в пострелизной доработке, второй мастер любит использовать аннотации. Однако использование аннотаций будет более разрозненным, а не таким централизованным, как файлы конфигурации. Эй, благожелательный видит благоволение, а мудрый видит мудрость.