zoukankan      html  css  js  c++  java
  • java注解

    注解(Annotation)

    Java中的注解是相当重要的知识点,在许多框架尤其是SpringBoot框架,使用注解来替代配置文件,很大程度上减少了配置的麻烦。

    Java中的类,方法,变量,参数和包都可以被注解标注。然而注解本身并不具有任何逻辑功能,它的存在更像是一个标签,告诉别人应该对它标注的内容进行何种处理。

    比如我们常见的注解

    • @Override:检查该方法是否是重写方法
    • @Deprecated:标记过时方法。
    • @SuppressWarnings:指示编译器去忽略注解中声明的警告。

    java中注解都实现接口Annotation

    package java.lang.annotation;
    public interface Annotation {
    
        boolean equals(Object obj);
    
        int hashCode();
    
        String toString();
    
        Class<? extends Annotation> annotationType();
    }
    

    java中注解的定义形式

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

    要理解上面的注解形式,我们先要了解一下元注解

    元注解

    元注解就是可以注解到注解上的注解,是用来说明注解性质的基本注解。

    @Retention

    用来指定注解的保留策略,即注解的存活时间

    通过枚举类RetentionPolicy的值来指定

    package java.lang.annotation;
    public enum RetentionPolicy {
        SOURCE,            /*注解只保留在源码阶段,编译器处理完之后就没有该Annotation信息了  */
    
        CLASS,             /* 编译器将Annotation存储于类对应的.class文件中,但不会加载到JVM中。默认行为  */
    
        RUNTIME            /* 编译器将Annotation存储于class文件中,可保留到程序运行时,并且可由JVM读入,因此可以通过反射读取它们 */
    }
    

    上面所提到的@Override和@SupressWarnings注解的保留策略就是SOURCE,因为只有编写源代码时我们才需要警告,在编译过后便没有必要保留。

    常用的保留策略还是RUNTIME,毕竟我们通常需要在运行时对注解标注的内容进行相应的处理。

    @Target

    我们知道注解可以标注在类、方法、变量等,而@Target就是用来指定注解可以标注的类型。与枚举类型ElementType结合使用。

    package java.lang.annotation;
    
    public enum ElementType {
        TYPE,               /* 类、接口(包括注释类型)或枚举声明  */
    
        FIELD,              /* 字段声明(包括枚举常量)  */
    
        METHOD,             /* 方法声明  */
    
        PARAMETER,          /* 参数声明  */
    
        CONSTRUCTOR,        /* 构造方法声明  */
    
        LOCAL_VARIABLE,     /* 局部变量声明  */
    
        ANNOTATION_TYPE,    /* 注释类型声明  */
    
        PACKAGE,             /* 包声明  */
            
        TYPE_PARAMETER,		 /* 参数类型声明  1.8后新增*/
    	
        TYPE_USE			 /*TYPE和TYPE_PARAMETER的结合,1.8后新增 */
    }
    

    @Target可有可无,如果没有,若没有则该注解可以标注在任何地方;如果有,则该注解必须标注在指定的地方。

    @Documented

    类和方法的注解默认情况下是不出现在javadoc中的,使用该@Document修饰的注解,生成javadoc时会出现在javadoc中。

    @Inherited

    Inherited是继承的意思,如果一个类被用@Inherited标注的注解标注了的话,那么这个子类就会继承这个父类的注解。

    例如有一个注解Inheritable被@Inherited标注

    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @interface Inheritable{}
    

    有一个父类被@Inheritable标注

    @Inheritable
    class InheritedFather{}
    

    有一个继承父类的子类,这个子类没有用任何注解标注

    public class InheritedSun extends InheritedFather{
        public static void main(String[] args) {
            //结果为true
            System.out.println(InheritedSun.class.isAnnotationPresent(Inheritable.class));
        }
    }
    

    上面打印结果为true,说明子类继承了父类的注解

    @Repeatable

    可重复的意思,java1.8后加入的,这个注解说明可以在其标注的同一个地方多次使用这个注解。

    例如,您正在编写代码以使用计时器服务,以在每月的最后一天以及每个星期五的晚上11:00运行doPeriodicCleanup方法。代码如下:

    声明可重复注解

    import java.lang.annotation.Repeatable;
    
    @Repeatable(Schedules.class)
    public @interface Schedule {
      String dayOfMonth() default "first";
      String dayOfWeek() default "Mon";
      int hour() default 12;
    }
    

    声明容器注解,即可存放注解的注解。容器注解必须有value属性,类型为@Repeatable注解的注解数组

    public @interface Schedules {
        Schedule[] value();
    }
    

    标注在doPeriodicCleanup方法上

    @Schedule(dayOfMonth="last")
    @Schedule(dayOfWeek="Fri", hour="23")
    public void doPeriodicCleanup() { ... }
    

    注解的属性

    如上例子

    @Repeatable(Schedules.class)
    public @interface Schedule {
      String dayOfMonth() default "first";
      String dayOfWeek() default "Mon";
      int hour() default 12;
    }
    

    String为类型,dayOfMonth()为属性名,default指定默认值。

    使用形如@Schedule(dayOfWeek="Fri", hour="23")的格式来使用注解。

    如果注解只有一个value属性,可以将value省略,直接写值,例如@Repeatable。@Repeatable(Schedules.class)

    public @interface Repeatable {
        Class<? extends Annotation> value();
    }
    

    ,如果注解内无属性,括号也可省略。如@Override

    java常用注解

    • @Deprecated -- @Deprecated 所标注内容,不再被建议使用。
    • @Override -- @Override 只能标注方法,表示该方法覆盖父类中的方法。
    • @Documented -- @Documented 所标注内容,可以出现在javadoc中。
    • @Inherited -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性
    • @Retention -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
    • @Target -- @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
    • @SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。
    • @FunctionalInterface --函数式接口注解,这个是 Java 1.8 版本引入的新特性。函数式接口 (Functional Interface) 就是一个具有一个方法的普通接口。线程开发中常用的 Runnable 就是一个典型的函数式接口,上面源码可以看到它就被 @FunctionalInterface 注解。

    反射与注解

    上面已经了解了注解的定义与基本知识,注解最重要的便是对其标注的内容进行处理。

    下面便进行一个简单实例,使用一个注解标注在方法上,为方法内的参数赋值。

    首先,自定义注释

    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
        String[] value();
    }
    

    创建一个类

    public class Person {
        private String name;
        private String sex;
    
    	//将注释中的值赋给方法
        @MyAnnotation(value = {"张三","男"})
        public void setNameAndSex(String name,String sex){
            System.out.println(name + "," + sex);
        }
    }
    

    测试方法

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<Person> clazz = Person.class;
        Person person = new Person();
    	//通过反射获取方法
        Method method = clazz.getMethod("setNameAndSex", String.class, String.class);
        //如果方法被@MyAnnotation注解标注
        if (method.isAnnotationPresent(MyAnnotation.class)) {
            //获取这个方法的MyAnnotation注解
            MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
            //获取注解内的属性值
            String[] value = annotation.value();
            //将属性值当做参数执行方法
            method.invoke(person,value[0],value[1]);
        }
    
    }
    
  • 相关阅读:
    Go 命令行参数,JSON 序列化与反序列化
    Go 文件操作
    Go 多态
    Go 接口
    Go 面向对象三大特性
    Go 面向对象编程应用
    Go 结构体方法
    Go 面向对象之结构体
    Go Map
    vue安装 vue-cli安装
  • 原文地址:https://www.cnblogs.com/ylcc-zyq/p/12862938.html
Copyright © 2011-2022 走看看