制作平台网站费用,搜索百度指数,新闻型网站建设,专业做灰色关键词排名注解
大多数时候#xff0c;我们会使用注解#xff0c;而不是自定义注解。注解给谁用#xff1f;编译器 、给解析程序用注解不是程序的一部分#xff0c;可以理解为注解就是一个标签
主要的作用有以下四方面#xff1a; 生成文档#xff0c;通过代码里标识的元数据生成…注解
大多数时候我们会使用注解而不是自定义注解。注解给谁用编译器 、给解析程序用注解不是程序的一部分可以理解为注解就是一个标签
主要的作用有以下四方面 生成文档通过代码里标识的元数据生成 javadoc 文档。 编译检查通过代码里标识的元数据让编译器在编译期间进行检查验证。 编译时动态处理编译时通过代码里标识的元数据动态处理例如动态生成代码。 运行时动态处理运行时通过代码里标识的元数据动态处理例如使用反射注入实例。
注解的本质
package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;/*** 拥有宠物的信息* 宠物的名字* 宠物的年龄*/
Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
Target(java.lang.annotation.ElementType.TYPE)
public interface Pet {String name();int age();
}反编译后发现,注解本质上是一个 interface并且继承了 java.lang.annotation.Annotation这个接口.
➜ anno git:(master) ✗ javac Pet.java javap Pet
警告: 二进制文件Pet包含com.jj.anno.Pet
Compiled from Pet.java
public interface com.jj.anno.Pet extends java.lang.annotation.Annotation {public abstract java.lang.String name();public abstract int age();
}Java 注解Annotation是一种元数据形式提供有关程序代码的额外信息但这些信息不会影响代码的实际执行。注解可以用于类、方法、变量、参数等程序元素上以便在编译时、类加载时或运行时进行处理。
元注解
元注解Meta-Annotations是用于注解其他注解的注解。元注解提供了对注解进行更精细的控制和定义。
Retention
Retention 用于指定注解的保留策略即注解可以在何时可用。它可以被用于定义其他注解。
public enum RetentionPolicy {/*** Annotations are to be discarded by the compiler.*/SOURCE,/*** Annotations are to be recorded in the class file by the compiler* but need not be retained by the VM at run time. This is the default* behavior.*/CLASS,/*** Annotations are to be recorded in the class file by the compiler and* retained by the VM at run time, so they may be read reflectively.** see java.lang.reflect.AnnotatedElement*/RUNTIME
}Retention 元注解有一个 value 属性用于指定保留策略。可选的保留策略包括
RetentionPolicy.SOURCE注解仅在源代码级别可见在编译之后不会包含在编译后的字节码中。RetentionPolicy.CLASS注解在编译时保留在编译后的字节码中可见但在运行时不可通过 反射 获取注解信息默认值。RetentionPolicy.RUNTIME注解在运行时保留可以通过反射获取注解信息并根据注解的定义执行相应的代码对运行时的代码有影响。
自定义注解的保留策略如果不指定默认为 RetentionPolicy.CLASS。
编译器分别使用了 RuntimeInvisibleAnnotations 和 RuntimeVisibleAnnotations 属性去记录了 RetentionPolicy.CLASS 注解的方法 和 RetentionPolicy.RUNTIME 方法的注解信息。
Target
描述注解的作用位置
public enum ElementType {/** Class, interface (including annotation interface), enum, or record* declaration */TYPE,/** Field declaration (includes enum constants) */FIELD,/** Method declaration */METHOD,/** Formal parameter declaration */PARAMETER,/** Constructor declaration */CONSTRUCTOR,/** Local variable declaration */LOCAL_VARIABLE,/** Annotation interface declaration (Formerly known as an annotation type.) */ANNOTATION_TYPE,/** Package declaration */PACKAGE,/*** Type parameter declaration** since 1.8*/TYPE_PARAMETER,/*** Use of a type** since 1.8*/TYPE_USE,/*** Module declaration.** since 9*/MODULE,/*** Record component** jls 8.10.3 Record Members* jls 9.7.4 Where Annotations May Appear** since 16*/RECORD_COMPONENT;
}Documented
Documented 用于指定被它注解的注解是否应该包含在自动生成的 API 文档Javadoc中。它可以被用于定义其他注解。Documented 只是一个标记它本身并不会影响注解的使用和行为。只有在生成 API 文档时才会体现其作用。
通常情况下如果开发者希望在 API 文档中包含某个注解的信息就可以为该注解添加 Documented 元注解。如果不需要在 API 文档中包含注解信息可以不添加该注解。
Inherited
Inherited 用于指定被它注解的 Annotation 是否可以被子类继承。它可以被用于定义其他注解。
自定义注解
interface 是 Java 中用于创建自定义注解的关键字。使用 interface 可以定义一个新的注解类型并在注解中声明自定义的元素。
public interface 注解名 {// 注解元素声明
}在 interface 定义的花括号中可以声明注解的元素。
注解元素的定义类似于方法的定义包括元素的类型、名称和可选的默认值。
注解的属性
属性定义方式与接口中的方法声明方式一样,在注解声明了方法,就同时声明了同名属性变量.
属性的赋值
注解的属性就是接口中定义的方法,定义了属性,就要给属性赋值.
如果定义属性时,使用 default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值.如果注解只声明了一个方法,方法名为 value,则在使用的时候, value 可以省略.数组赋值时,值使用{}包裹如果数组中只有一个值,则{}省略
属性的返回值
基本数据类型String枚举注解以上类型的数组
注解解析
在 Java 这个纯面向对象的语言中一切的行为都是基于类的设计来描述对注解的解析也离不开其所注解的类。
解析注解主要还是要通过被注解的对象的class、method、field来获取。
类上注解解析
在注解的作用对象为Target(ElementType.TYPE)的基础上。
解析步骤为 获取类字节码信息 获取该class上的注解信息 解析得到注解信息
解析属性上面的字节
在注解的作用对象为Target(ElementType.FIELD)的基础上。
解析步骤为 获取类字节码信息 获取字节码中的属性 获取该属性上的注解信息 解析得到注解信息
自定义案例
定义一个枚举
package com.jj.anno;public enum Enumeration {//星期MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}作用在字段上
package com.jj.anno;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;/*** 地址注解*/
Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
Target(ElementType.FIELD)
public interface AddressAnnotation {String value() default ;
}作用在字段上
package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;/*** 名字注解*/
Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
Target(java.lang.annotation.ElementType.FIELD)
public interface NameAnnotation {String name() default ;
}作用在类型上
package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;/*** 拥有宠物的信息* 宠物的名字* 宠物的年龄*/
Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
Target(java.lang.annotation.ElementType.TYPE)
public interface Pet {String name();int age();
}
作用在方法上
package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
Target(java.lang.annotation.ElementType.METHOD)
public interface MethodAnnotation {String value() default ;
}
作用在类型上
package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
Target(java.lang.annotation.ElementType.TYPE)
public interface Staff {//薪水int value();//岗位名字String title() default 程序员;//工龄int workAge() default 1;Enumeration weekday() default Enumeration.MONDAY;String[] hobbies();AddressAnnotation address();NameAnnotation nickname();Pet pet();
}使用注解
package com.jj.bean;import com.jj.anno.*;Pet(name jj, age 18)
Staff(value 180000,title IT 工程师,workAge 10,weekday Enumeration.MONDAY,address AddressAnnotation(上海市),nickname NameAnnotation(name 云溪),pet Pet(name jj, age 18),hobbies {打游戏, 看电影})
public class MyPerson {NameAnnotation(name 石昊)private String name;AddressAnnotation(value 上海市宝山区)private String address;public String getName() {return name;}
}注解解析
package com.jj.bean;import com.jj.anno.*;import java.lang.reflect.Field;public class Main {public static MyPerson initObj() {MyPerson myPerson new MyPerson();ClassMyPerson clazz MyPerson.class;if (clazz.isAnnotationPresent(Pet.class)) {Pet pet clazz.getAnnotation(Pet.class);System.out.println(宠物的名字 pet.name());System.out.println(宠物的年龄 pet.age());}if (clazz.isAnnotationPresent(Staff.class)) {Staff staff clazz.getAnnotation(Staff.class);System.out.println(岗位名字 staff.title());System.out.println(工龄 staff.workAge());String[] hobbies staff.hobbies();for (String hobby : hobbies) {System.out.println(兴趣爱好 hobby);}Pet pet staff.pet();System.out.println(宠物的名字 pet.name());System.out.println(宠物的年龄 pet.age());Enumeration weekday staff.weekday();System.out.println(工作日 weekday);NameAnnotation name staff.nickname();System.out.println(staff 的 名字 name.name());AddressAnnotation address staff.address();System.out.println(staff 的 地址 address.value());}Field[] fields clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true); // 确保可以访问私有字段if (field.isAnnotationPresent(NameAnnotation.class)) {NameAnnotation annotation field.getAnnotation(NameAnnotation.class);System.out.println(名字 annotation.name());try {field.set(myPerson, annotation.name());} catch (IllegalAccessException e) {throw new RuntimeException(e);}}if (field.isAnnotationPresent(AddressAnnotation.class)) {AddressAnnotation annotation field.getAnnotation(AddressAnnotation.class);System.out.println(地址 annotation.value());}}return myPerson;}public static void main(String[] args) {MyPerson myPerson initObj();System.out.println(通过注解和反射创建的对象 myPerson.getName());}
}