Java源码赏析(四)Java常见注解
元注解
@Target :标识注解的目标,默认为所有
-
ElementType.TYPE(用于类)
-
ElementType.FIELD(用于域,包括enum)
-
ElementType.METHOD(用于方法)
-
ElementType.PARAMETER(用于正式参数)
-
ElementType.CONSTRUCTOR(类型构造方法)
-
ElementType.LOCAL_VARIABLE(用于本地变量)
-
ElementType.ANNOTATION_TYPE(用于注解)
-
ElementType.PACKAGE(用于包)
-
ElementType.TYPE_PARAMETER(java8,用于输入参数)
-
ElementType.TYPE_USE (java8,用于类型)
@Retention:注解保留到哪
- RetentionPolicy.SOURCE (只保留到源码,编译为.class文件时忽略)
- RetentionPolicy.CLASS (只保留到.class文件,运行时忽略,default默认)
- RetentionPolicy.RUNTIME (运行时保留,可以通过反射机制读取注解的信息。)
@Documented:将此注解保存在 Javadoc 中
@Inherited:允许子类继承父类的注解
@Repeatable:用于重复使用注解(Java8新增)
常用注解
一、@Override
常用于重写父类的方法,或实现接口的方法,若不满足则报错。
package java.lang; import java.lang.annotation.*; /** * 使用在方法上,只存在在源码上 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
二、@Deprecated
常用于标注一个方法被弃用。
package java.lang; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; /** * 记录JavaDoc,保留至运行时,可使用在构造方法,属性(包括枚举),本地变量,方法,包,公共参数和类 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }
三、@SuppressWarnings
常用于忽略特定警告,@SuppressWarnings("unchecked", "deprecation")可以同时忽略多个警告。
package java.lang; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; /** * 在类型、域、方法、正是参数、构造方法、本地变量上使用,只存在于源码 */ @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { /** * 一般取 unchecked/deprecation,表示忽略 unchecked/deprecation 警告信息 */ String[] value(); }
四、@SafeVarargs (Java7)
常用于抑制varargs相关的未检查警告,一般只能用于static、final方法
package java.lang; import java.lang.annotation.*; /** * 能记录JavaDoc,保留至运行时,使用在构造方法和方法上 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.CONSTRUCTOR, ElementType.METHOD}) public @interface SafeVarargs {}
五、@FunctionalInterface (Java8)
编译器检测接口是否符合函数式接口定义
package java.lang; import java.lang.annotation.*; /** * 能记录JavaDoc,存在于运行时,只能使用在类上 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FunctionalInterface {}
自定义注解
首先定义一个注解
package com.example.demo.util.annotation; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Documented @Inherited public @interface MyAnnotation { String value() default "001"; }
可以看到,在Student的sNo属性上使用了该注解
package com.example.demo.util.annotation; import lombok.Data; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Student { @MyAnnotation private String sNo; private String sName; }
处理注解
package com.example.demo.util.annotation; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Objects; public class AnnotationTest { public static void main(String[] args) { //创建一个学号为 002 的学生 kw Student student = new Student("002", "kw"); //获取学生对象对应的类 Class<? extends Student> clazz = student.getClass(); //获取学生类的属性 Field[] declaredFields = clazz.getDeclaredFields(); /** 循环判断是否存在注解@MyAnnotation * 若存在则获取该属性的set方法 * 并使用该方法将值改为@MyAnnotation的value值 */ @MyAnnotation的value for (Field field: declaredFields) { if (field.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation annotation = field.getAnnotation(MyAnnotation.class); if (Objects.nonNull(annotation)) { String name = field.getName(); try { Method setMethod = clazz.getDeclaredMethod( "set" + name.substring(0, 1).toUpperCase() + name.substring(1), String.class); String annotationValue = annotation.value(); setMethod.invoke(student, annotationValue); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } } //打印 System.out.println(student); } } /** 输出 Student(sNo=001, sName=kw) */