一文带你领略Java注解(Annotation)的魅力

Java注解(Annotation)

什么是注解?

AnnotationJava5开始引入的新特征,中文名称叫注解。它用来将元数据metadata)与程序元素(类、方法、成员变量等)进行关联。注解为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。

Java注解是附加在代码中的一些元数据,用于一些工具编译、运行时进行解析==(通过反射)==和使用,起到说明、配置的功能。注解不能直接干扰程序代码的运行,无论增加或者删除注解,代码都能正常运行

注解的用处

  1. 编写文档:通过代码里标识的元数据生成文档。常见有@param @return等。
  2. 代码分析:通过代码里面标识元数据对代码进行分析。
  3. 编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。

系统注解

标准注解

Java提供了5个基本的注解用法

  • @Override:限定重写父类方法,它可以强制一个子类必须覆盖父类的方法。写在子类的方法上,在编译期,编译器检查这个方法,检查父类必须包含该方法,否则编译出错。该注解只能修饰方法,在编译期被读取

  • @Deprecated:用于表示某个程序元素已过时或者可能运行时出现问题。编译时读取,编译器编译到过时元素会给出警告

  • @SuppressWarnings:抑制编译警告。被该注解修饰的程序元素(以及该程序元素中的所有子元素)取消显式指定的编译警告

  • @SafeVarargs:Java7新增,去除“堆污染”警告堆污染-------把一个不带泛型的对象赋值给一个带泛型的变量时就会发生堆污染。

    List l2 = new ArrayList<Number>();
    List<String> ls = l2; 
    
    Arrays源代码
    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
      return new ArrayList<>(a);
    }
    
  • @FunctionInterfaceJava8新增,修饰函数式接口。使用该注解修饰的接口必须是函数式接口,不然编译会出错函数式接口------如果接口中只有一个抽象方法(可以包含多个default方法或者static方法),就是函数式接口。

    @Functionlnterface
    public interface FunInterface{
      static void foo(){
       System.out.println("foo类方法");
      }
      default void bar(){
       System.out.println("bar默认方法");
      }
      void test();//只定义一个抽象方法,默认public
    }
    

元注解

元注解:和元数据一样,修饰注解的注解。

  • @Target(目标)

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        /**
         * Returns an array of the kinds of elements an annotation type
         * can be applied to.
         * @return an array of the kinds of elements an annotation type
         * can be applied to
         */
        ElementType[] value();
    }
    

    用于指定被修饰的注解能用于哪些程序元素上。它包含一个名为value的成员变量,取值如下:

    public enum ElementType {
        /** Class, interface (including annotation type), or enum declaration */
        TYPE,
    
        /** Field declaration (includes enum constants) */
        FIELD,
    
        /** Method declaration */
        METHOD,
    
        /** Formal parameter declaration */
        PARAMETER,
    
        /** Constructor declaration */
        CONSTRUCTOR,
    
        /** Local variable declaration */
        LOCAL_VARIABLE,
    
        /** Annotation type declaration */
        ANNOTATION_TYPE,
    
        /** Package declaration */
        PACKAGE,
    
        /**
         * Type parameter declaration
         *
         * @since 1.8
         */
        TYPE_PARAMETER,
    
        /**
         * Use of a type
         *
         * @since 1.8
         */
        TYPE_USE
    }
    
  • @Retention(保留)

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
        /**
         * Returns the retention policy.
         * @return the retention policy
         */
        RetentionPolicy value();
    }
    

    用于指定被修饰注解的生命周期。它包含一个value的成员变量,取值如下:

    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
    }
    
    SOURCE在编译阶段被丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码文件。@Override、@SuppressWarnings都属于这类注解。
    CLASS在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
    RUNTIME始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解信息。
  • @Documented

    用于指定被修饰的注解将被Javadoc工具取成文档,即说明该注解将被包含在Javadoc中。

  • @Inherited

    用于指定被修饰的注解具有继承性。即子类可以继承父类中的该注解。

自定义注解

使用关键字@interface

注解元素数据类型

  1. 所有基本类型(int、float、boolean等)
  2. String
  3. Class
  4. enum
  5. Annotation
  6. 以上类型的数组

一个简单的注解

@interface test{}

默认情况下,注解可以修饰任何程序元素(类、方法、接口、属性)等。

带成员变量的注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
     String name();
     int id() default 0;
}

@DBTable(name = "student")
public class Test01 {
}

以无形参的方法形式来声明注解的成员变量。使用default关键字设置初始值,没设置初始值的变量则使用时必须提供,有初始值的变量可以设置也可以不设置。

结论

  • 没有成员变量的注解 ----标记注解(marker annotation)这种注解仅利用自身的存在与否来提供信息
  • 有成员变量的注解----单值注解、完整注解 这种注解提供更多元数据

获取注解信息

思路:通过反射获取注解,将注解转换成具体的注解类,在调用注解类定义的方法获取元数据信息。

java.lang.reflect.AnnotatedElement接口 代表程序中可以接受注解的程序元素。常见实现类:

  • Class:类定义
  • Constructor:构造器定义
  • Field:类的成员属性定义
  • Method:类的方法定义
  • Package:类的包定义

AnnotatedElement接口获取注解信息的方法如下:

    • Modifier and TypeMethod and Description
      <T extends Annotation>TgetAnnotation(Class<T> annotationClass) 返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。
      Annotation[]getAnnotations() 返回此元素上 存在的注释。
      default <T extends Annotation>T[]getAnnotationsByType(Class<T> annotationClass) 返回与此元素相关 联的注释
      default <T extends Annotation>TgetDeclaredAnnotation(Class<T> annotationClass) 如果这样的注释 直接存在 ,则返回指定类型的元素注释,否则返回null。
      Annotation[]getDeclaredAnnotations() 返回 直接存在于此元素上的注释。
      default <T extends Annotation>T[]getDeclaredAnnotationsByType(Class<T> annotationClass) 如果此类注释 直接存在或 *间接存在,*则返回该元素的注释(指定类型)。
      default booleanisAnnotationPresent(Class<? extends Annotation> annotationClass) 如果此元素上 存在指定类型的注释,则返回true,否则返回false。

举例

注解处理器

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBField {
    int id() default 0;
    String value();
}


public class Test01 {

    public static void main(String[] args) throws Exception{
        User user = new User();
        Class clazz = user.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields){
           DBField dbField =  field.getAnnotation(DBField.class);
           System.out.println("id = "+dbField.id()+"\t"+"value = "+dbField.value());
       }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值