注解说明
Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据。为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。
Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取注解内容。在编译器生成类文件时,注解可以被嵌入到字节码中。Java虚拟机可以保留注解内容,在运行时可以获取到注解内容。
2|1内置注解
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
1、作用在代码的注解是
@Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。
2、作用在其他注解的注解(或者说元注解)是:
@Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
@Documented - 标记这些注解是否包含在用户文档中。
@Target - 标记这个注解应该是哪种 Java 成员。
@Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
3、从 Java 7 开始,额外添加了 3 个注解:
@SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
@FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
@Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
2|2元注解
1、@Retention
@Retention annotation指定标记注释的存储方式:
RetentionPolicy.SOURCE - 标记的注释仅保留在源级别中,并由编译器忽略。
RetentionPolicy.CLASS - 标记的注释在编译时由编译器保留,但Java虚拟机(JVM)会忽略。
RetentionPolicy.RUNTIME - 标记的注释由JVM保留,因此运行时环境可以使用它。
2、@Documented
@Documented 注释表明,无论何时使用指定的注释,都应使用Javadoc工具记录这些元素。(默认情况下,注释不包含在Javadoc中。)有关更多信息,请参阅 Javadoc工具页面。
3、@Target
@Target 注释标记另一个注释,以限制可以应用注释的Java元素类型。目标注释指定以下元素类型之一作为其值
ElementType.TYPE 可以应用于类的任何元素。
ElementType.FIELD 可以应用于字段或属性。
ElementType.METHOD 可以应用于方法级注释。
ElementType.PARAMETER 可以应用于方法的参数。
ElementType.CONSTRUCTOR 可以应用于构造函数。
ElementType.LOCAL_VARIABLE 可以应用于局部变量。
ElementType.ANNOTATION_TYPE 可以应用于注释类型。
ElementType.PACKAGE 可以应用于包声明。
ElementType.TYPE_PARAMETER
ElementType.TYPE_USE
4、@Inherited
@Inherited 注释表明注释类型可以从超类继承。当用户查询注释类型并且该类没有此类型的注释时,将查询类的超类以获取注释类型(默认情况下不是这样)。此注释仅适用于类声明。
5、@Repeatable
Repeatable Java SE 8中引入的,@Repeatable注释表明标记的注释可以多次应用于相同的声明或类型使用(即可以重复在同一个类、方法、属性等上使用)。
自定义注解:
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
定义注解格式:
public @interface 注解名 {定义体}
注解参数的可支持数据类型:
1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String类型
3.Class类型
4.enum类型
5.Annotation类型
6.以上所有类型的数组
Annotation类型里面的参数该怎么设定:
第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。
注解处理器类库(java.lang.reflect.AnnotatedElement):
AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下四个个方法来访问Annotation信息:
注解处理的一个基础:
方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
方法2:Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。
实例
上面的定义解释比较繁琐,下面来看看一段简单的示例代码,相信立马就可以理解了:
步骤一:定义两个自定义注解,用来修饰属性,一个标注名字,一个标注性别。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Name {//名字自定义注解
public String value() default "";
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Sex {//性别自定义注解
public enum GenderType {
Male("男"),
Female("女");
private String genderStr;
private GenderType(String arg0) {
this.genderStr = arg0;
}
@Override
public String toString() {
return genderStr;
}
}
GenderType gender() default GenderType.Male;
}
步骤二:自定义注解标注在属性上
public class Person {
@Name(value = "cool_summer_moon")
public String name;
public String age;
@Sex(gender = Sex.GenderType.Male)
public String sex;
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
步骤三:定义一个测试工具类,取刚才标注的属性值
import java.lang.reflect.Field;
public class AnnotionUtils {
public static String getInfo(Class<?> cs){
String result = "";
Field[] declaredFields = cs.getDeclaredFields();
for (Field field : declaredFields){
if(field.isAnnotationPresent(Name.class)){
Name annotation = field.getAnnotation(Name.class);
String value = annotation.value();
result += (field.getName() + ":" + value + "\\n");
}
if(field.isAnnotationPresent(Sex.class)){
Sex annotation = field.getAnnotation(Sex.class);
String value = annotation.gender().name();
result += (field.getName() + ":" + value + "\\n");
}
}
return result;
}
public static void main(String[] args){
String info = getInfo(Person.class);
System.out.println(info);
}
}
运行上面程序,结果如下:
name:cool_summer_moon
sex:Male
参考:
https://blog.csdn.net/wangpengzhi19891223/article/details/78131137/
https://www.cnblogs.com/jajian/p/9695055.html#autoid-3-0-0