Java基础:Java注解(Annotation)及使用

star2017 1年前 ⋅ 381 阅读

Java 注解(Annotation)是 JDK 1.5 引入的特性,与类、接口、枚举是在同一等级。它可以作用在类、属性、方法、局部变量、方法参数上,用于对这些元素进行说明,注释,解释。

注解在功能上可以看成是一个接口,注解实例就是一个实现该接口的动态代理类,可在方便在程序运行期间通过反射获取该字段或方法的注解的实例,来决定下一步如何处理。

注解定义

注解 是一种标记,一种标注,一个极期相似的比喻就是标签纸,用于对其作用的目标对象进行说明,以便进行对应的操作。

有了注解,还需要对这些注解进行解析,可以通过反射机制(Reflect)访问这些注解并对其进行解析(注解解析类),没有解析的注解不起任何作用,没有任何意义的,但也不会影响代码的执行。

所有 注解 类型都继承 java.lang.annotation.Annotation 公共接口。注解的使用越来越流行,Spring Boot 框架就提供了大量的注解,由 SSM 框架的 XML 配置转为 Java 配置类,注解扮演很重要的角色,非常方便且代码更加简洁。

基本注解

定义注解与定义接口相似,只是在接口名前需要前使用 @ 符号。Java 5 内置了三种基本注解:

  • @Override:当前方法重写父类中的方法。
  • @Deprecated:标记该目标已被弃用,不建议使用,或存在更好的替代方案。
  • @SuppressWarnings:抑制编译器的警告信息。

Java 8 新增了一种注解:

  • @Repeatable:支持同一个注解可重复在同一类/方法/属性上使用,更低的版是不支持的。

元注解

元注解 :作用在注解上的注解,编译器自动会对这种类注解进行解析。 JDK 提供的元注解有 @Retention@Target@Documented@Inherited四个。

Spring 框架提供的很多注解,也使用了元注解。例如 Spring Boot 入口类的注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    //-----省略---------------
}

@Target

标记此类型的注解应该作用在那种 Java 成员上。该元注解只有一个属性,引用的是 java.lang.annotation.ElementType 枚举中的值。

  1. @Target

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        ElementType[] value();
    }
    
  2. ElementType

    public enum ElementType {
        /**
         * 类,接口,枚举声明
         */
        TYPE,
        /**
         * 字段声明(包括枚举值)
         */ 
        FIELD,
        /**
         * 方法声明
         */ 
        METHOD,
        /**
         * 方法参数声明
         */ 
        PARAMETER,
        /**
         * 构造方法声明
         */ 
        CONSTRUCTOR,
        /**
         * 局部变量声明
         */ 
        LOCAL_VARIABLE,
        /**
         * 注解类型声明
         */ 
        ANNOTATION_TYPE,
        /**
         * 包声明
         */ 
        PACKAGE,
        TYPE_PARAMETER,
        TYPE_USE
    }
    

@Retention

标记此类型的注解将保留多长时间(保留级别,或称为注解生命周期)。如果注解没有使用此元注解,则保留策略默认为 RetentionPolicy.CLASS

该元注解只有一个属性,引用的是 java.lang.annotation.RetentionPolicy 的枚举值。

  1. @Retention

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
        RetentionPolicy value();
    }
    
  2. RetentionPolicy

    public enum RetentionPolicy {
        /**
         * 只在源码中保留,将被编译器丢弃
         */
        SOURCE,
    
        /**
         * 编译时会记录到CLASS文件中,但运行时忽略,默认行为。
         */
        CLASS,    
    
        /**
         * 编译时会记录到CLASS文件中,并在运行时由 JVM 保留,可以通过反射读取它们。
         * @see java.lang.reflect.AnnotatedElement
         */
        RUNTIME
    }
    

@Document

标记将注解包含在 Javadoc 中。指示默认情况下,javadoc 和类似工具将记录带有此类型的注解,成为公共API 的一部分。

类和方法的注解,在默认情况下是不出现在 javadoc 中的。如果使用 @Document 修饰该注解,则表示此注解会出现在 javadoc 中。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Inherited

标记该注解是具有继承性的,使用该元注解的注解作用的目标类的子类具体父类的注解特性。只能作用在 Annotation 类型上。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

注解作用

注解的作用大致可分为三类:

  • 生成文档:标识目标代码需要生成文档(doc)。
  • 代码分析:标识对代码进行解析,使用反射实现。
  • 编译检查:标识编译器可对代码进行最基本的编译检查。

注解使用

注解只有一个成员时,按规范写成 value(),当然不这么写也不会报错。如果不设置默认值,那么使用注解时必须要传值。只有类可以被注解,接口或抽象类不能被注解。

自定义注解

自定义一个对用户年龄范围进行校验的注解,实现用户年龄范围的控制和提示。

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AgeRange {

    int max() default 120;

    int min() default 0;
}

注解解析

  1. 定义一个用户类 User.class

    public class User {
    
        private String name;
        @AgeRange(max = 45, min = 18)
        private int age;
    }
    
  2. 对注解进行解析

    public static void main(String[] args) {
        User user = new User().setAge(11);
    
        Class<User> userClass = User.class;
        Field[] fieldArray = userClass.getDeclaredFields();
        for (Field field : fieldArray) {
            AgeRange ageRange = field.getDeclaredAnnotation(AgeRange.class);
    
            if (ageRange != null) {
                if (user.getAge() > ageRange.max() || user.getAge() < ageRange.min())
                    System.out.println("用户年龄必须在 18 到 45 之间");
            }
        }
    }
    

读取注解

//读取注解信息
public class ReadAnnotationInfoTest {
    public static void main(String[] args) throws Exception {
        // 测试AnnotationTest类,得到此类的类对象
        Class c = Class.forName("com.iwtxokhtd.annotation.AnnotationTest");
        // 获取该类所有声明的方法
        Method[] methods = c.getDeclaredMethods();
        // 声明注解集合
        Annotation[] annotations;
        // 遍历所有的方法得到各方法上面的注解信息
        for (Method method : methods) {
            // 获取每个方法上面所声明的所有注解信息
            annotations = method.getDeclaredAnnotations();
            // 再遍历所有的注解,打印其基本信息
            System.out.println(method.getName());
            for (Annotation an : annotations) {
                System.out.println("方法名为:" + method.getName() + "其上面的注解为:" + an.annotationType().getSimpleName());
                Method[] meths = an.annotationType().getDeclaredMethods();
                // 遍历每个注解的所有变量
                for (Method meth : meths) {
                    System.out.println("注解的变量名为:" + meth.getName());
                }
            }
        }
    }
}

其它参考

  1. Java 注解(Annotation)
  2. Java 注解 annotation
更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: