• Java 注解(Annotation)


    一、注解(Annotation)

      1、概述

        (1)JDK 5.0 开始, Java 增加了对元数据(MetaData) 的支持, 也就是Annotation(注解);

        (2)Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。通过使用 Annotation, 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。 代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证
    或者进行部署。

        (3)Annotation 可以像修饰符一样被使用, 可用于修饰包,, 构造器, 方法, 成员变量, 参数, 局部变量的声明, 这些信息被保存在 Annotation“name=value” 对中。

        (4)JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android中注解占据了更重要的角色,例如用来配置应用程序的任何切面, 代替JavaEE旧版中所遗留的繁冗代码和XML配置等。

        (5)未来的开发模式都是基于注解的, JPA是基于注解的, Spring2.5以上都是基于注解的, Hibernate3.x以后也是基于注解的,现在的Struts2有一部分也是基于注解的了,注解是一种趋势,一定程度上可以说: 框架 = 注解 + 反射 + 设计模式。

        (6)注解(Annotation),也叫元数据。一种代码级别的说明。它是 JDK1.5 及以后版本引入的一个特效,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等前面,用来对这些元素进行说明,注释。

      2、注解作用

         代码分析:通过代码里标识的注解对代码进行分析【使用反射】

         编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】

     

    二、常见的 Annotation 示例

      1、注解的使用

        使用 Annotation 时要在其前面增加 @ 符号, 把该 Annotation 当成一个修饰符使用。 用于修饰它支持的程序元素。

      2、示例一:生成文档相关的注解

        说明:

    @author 标明开发该类模块的作者, 多个作者之间使用,分割
    @version 标明该类模块的版本
    @see 参考转向, 也就是相关主题
    @since 从哪个版本开始增加的
    @param 对方法中某参数的说明, 如果没有参数就不能写
    @return 对方法返回值的说明, 如果方法的返回值类型是void就不能写
    @exception 对方法可能抛出的异常进行说明 , 如果方法没有用throws显式抛出的异常就不能写
    

          其中:

          @param @return @exception 这三个标记都是只用于方法的。
          @param的格式要求: @param 形参名 形参类型 形参说明
          @return 的格式要求: @return 返回值类型 返回值说明
          @exception的格式要求: @exception 异常类型 异常说明
          @param@exception可以并列多个

        Demo:

     1 package com.njf.javadoc;
     2 
     3 /**
     4  * @author niujifei
     5  * @version 1.0
     6  * @see Math.java
     7  */
     8 public class JavadocTest {
     9     /**
    10      * 程序的主方法,程序的入口
    11      * @param args String[] 命令行参数
    12      */
    13     public static void main(String[] args) {
    14     }
    15     /**
    16      * 求圆面积的方法
    17      * @param radius double 半径值
    18      * @return double 圆的面积
    19      */
    20     public static double getArea(double radius){
    21         return Math.PI * radius * radius;
    22     }
    23 }

    可以使用 javadoc  文件名.java  来生成 doc 文档(通过代码里标识的注解生成文档)

      

      3、示例二:在编译时进行格式检查(JDK内置的三个基本注解)

        说明:

    @Override: 限定重写父类方法, 该注解只能用于方法,检测被该注解标注的方法是否是继承自父类(接口)的,它只能用在方法上面,会让编译器对这个方法进行格式检查,是否满足重写的要求。
    @Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
    @SuppressWarnings: 抑制编译器警告,一般传递参数 all,压制所有的警告(@SuppressWarnings("all"))
    

        Demo:

     1 public class AnnotationTest{
     2     public static void main(String[] args) {
     3         @SuppressWarnings("unused")  //表示压制警告,可以作用与类与方法或变量
     4         int a = 10;
     5     }
     6     @Deprecated    //表示方法已经过时了,但是不能删除,为了向下兼容
     7     public void print(){
     8         System.out.println("过时的方法");
     9     }
    10     @Override
    11     public String toString() {
    12         return "重写的toString方法()";
    13     }
    14 }

      4、示例三:跟踪代码依赖行,实现替代配置文件功能

        说明:Servlet3.0提供了注解(annotation),使得不再需要在web.xml文件中进行Servlet的部署。

        Demo:

     1 @WebServlet("/login")
     2 public class LoginServlet extends HttpServlet {
     3     private static final long serialVersionUID = 1L;
     4 
     5     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
     6             ServletException, IOException {
     7     }
     8 
     9     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
    10             ServletException, IOException {
    11         doGet(request, response);
    12     }
    13 }
    1 <servlet>
    2     <servlet-name>LoginServlet</servlet-name>
    3     <servlet-class>com.servlet.LoginServlet</servlet-class>
    4 </servlet>
    5 <servlet-mapping>
    6     <servlet-name>LoginServlet</servlet-name>
    7     <url-pattern>/login</url-pattern>
    8 </servlet-mapping>

       Spring 框架中关于“事务”的管理:

     1     @Transactional(propagation = Propagation.REQUIRES_NEW,
     2             isolation = Isolation.READ_COMMITTED, readOnly = false, timeout = 3)
     3     public void buyBook(String username, String isbn) {
     4         //1.查询书的单价
     5         int price = bookShopDao.findBookPriceByIsbn(isbn);
     6         //2. 更新库存
     7         bookShopDao.updateBookStock(isbn);
     8         //3. 更新用户的余额
     9         bookShopDao.updateUserAccount(username, price);
    10     }
    1 <!-- 配置事务属性 -->
    2 <tx:advice transaction-manager="dataSourceTransactionManager" id="txAdvice">
    3     <tx:attributes>
    4         <!-- 配置每个方法使用的事务属性 -->
    5         <tx:method name="buyBook" propagation="REQUIRES_NEW" isolation="READ_COMMITTED" read-only="false" timeout="3"/>
    6     </tx:attributes>
    7 </tx:advice>

      5、Junit 相关的注解

        (1)@Test :表示它是一个单元测试方法

           这个方法需要是: 

    public void xxx() {}

        (2)@Before:表示在每一个单元测试方法之前执行

           这个方法需要是:

    public void xxx() {}

       (3)@After:表示在每一个单元测试方法之后执行

           这个方法需要是:

    public void xxx() {}

       (4)@BeforeClass:表示在类初始化阶段执行,而且只执行一次

          这个方法需要是:

    public static void xxx() {}

        (5)@AfterClass:表示在类的“卸载”阶段执行,而且只执行一次

             这个方法需要是:

    public static void xxx(){}
    

      

    三、JDK 中的元注解

      1、元注解概述

        元注解:用于描述注解的注解,对现有的注解进行解释说明的注解

        JDK 的元 Annotation 用于修饰其他 Annotation 定义;

        JDK5.0提供了4个标准的meta-annotation类型, 分别是:

        ① Retention;

        ② Target;

        ③ Document;

        ④ Inherited;

      2、Retention 元注解

        @Retention:只能用于修饰一个 Annotation 定义,用于指定该 Annotation 的生命周期,@Retention 包含一个 RetentionPolicy 类型的成员变量,使用 @Retention 时必须为该 value 成员变量指定值:

        ① RetentionPolicy.SOURCE:在源文件中有效(即源文件保留) , 编译器直接丢弃这种策略的注解;

        ② RetentionPolicy.CLASS:class文件中有效(即class保留) , 当运行 Java 程序时, JVM不会保留注解。 这是默认值

        ③ RetentionPolicy.RUNTIME:在运行时有效(即运行时保留) , 当运行 Java 程序时, JVM 会保留注释。程序可以通过反射获取该注解。

           

         源码:

     1 public enum RetentionPolicy {
     2     /**
     3      * Annotations are to be discarded by the compiler.
     4      */
     5     SOURCE,    //当前被描述的注解,不会存在 class 字节码文件中(不常用)
     6 
     7     /**
     8      * Annotations are to be recorded in the class file by the compiler
     9      * but need not be retained by the VM at run time.  This is the default
    10      * behavior.
    11      */
    12     CLASS,    //当前被描述的注解,会保留到class字节码文件中,但是不会被JVM读取。(不常用)
    13 
    14     /**
    15      * Annotations are to be recorded in the class file by the compiler and
    16      * retained by the VM at run time, so they may be read reflectively.
    17      *
    18      * @see java.lang.reflect.AnnotatedElement
    19      */
    20     RUNTIME    //当前被描述的注解,会保留到class字节码文件中,并被JVM读取到(自定义常用)
    21 }

      3、Target 元注解

        @Target: 用于修饰 Annotation 定义, 用于指定被修饰的 Annotation 能用于修饰哪些程序元素。

        @Target 也包含一个名为 value 的成员变量。

        Target 里面是一个 ElementType[] value() 的枚举数组,这个数组里面指定了10个常量对象。

        

        源码:

     1 public enum ElementType {
     2     /** Class, interface (including annotation type), or enum declaration */
     3     TYPE,           //表示可以作用与类、接口上
     4 
     5     /** Field declaration (includes enum constants) */
     6     FIELD,          // 表示可以作用于成员变量上
     7 
     8     /** Method declaration */
     9     METHOD,         // 表示可以作用与方法上
    10 
    11     /** Formal parameter declaration */
    12     PARAMETER,
    13 
    14     /** Constructor declaration */
    15     CONSTRUCTOR,
    16 
    17     /** Local variable declaration */
    18     LOCAL_VARIABLE,
    19 
    20     /** Annotation type declaration */
    21     ANNOTATION_TYPE,
    22 
    23     /** Package declaration */
    24     PACKAGE,
    25 
    26     /**
    27      * Type parameter declaration
    28      *
    29      * @since 1.8
    30      */
    31     TYPE_PARAMETER,
    32 
    33     /**
    34      * Use of a type
    35      *
    36      * @since 1.8
    37      */
    38     TYPE_USE
    39 }

        

      4、Document 元注解

        @Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被javadoc 工具提取成文档。

        默认情况下,javadoc 是不包括注解的。

        注意定义为Documented的注解必须设置Retention值为RUNTIME

      5、Inherited 元注解

         @Inherited: 被它修饰的 Annotation 将具有继承性。如果某个类使用了被@Inherited 修饰的 Annotation, 则其子类将自动具有该注解。

        比如:如果把标有@Inherited注解的自定义的注解标注在类级别上,子类则可以继承父类类级别的注解;

        实际应用中,使用较少;

    四、JDK8 中注解的新特性

    Java 8对注解处理提供了两点改进: 可重复的注解可用于类型的注解。此外,反射也得到了加强,在Java8中能够得到方法参数的名称。这会简化标注在方法
    参数上的注解。

      1、可重复注解

        可重复注解:注解可以重复定义多个。

        JDK8之前的实现方式:

        如果要实现这样的效果,JDK8之前是不能这样声明的,但是我们可以声明一个包含 @MyAnnotation 数组的 @MyAnnotations 的注解,然后给赋值。

        

         声明两个注解:

     1 @Retention(RetentionPolicy.RUNTIME)
     2 @Target(ElementType.TYPE)
     3 public @interface MyAnnotation {
     4     String value() default "java";
     5 }
     6 
     7 
     8 --------------------------------------
     9 @Retention(RetentionPolicy.RUNTIME)
    10 @Target(ElementType.TYPE)
    11 public @interface MyAnnotations {
    12 
    13     MyAnnotation[] value();
    14 }

        然后使用 @MyAnnotations 注解来修饰:

        JDK8之后的实现方式:

          JDK8之后又提供了一个@Repeatable注解,可以重复声明注解。

          使用方式:

            ① 在MyAnnotation上声明@Repeatable,成员值为MyAnnotations.class;

            ② MyAnnotation的Target和Retention等元注解与MyAnnotations相同;(元注解要相同)

          声明两个注解:

     1 @Repeatable(MyAnnotations.class)      //需要与哪个类型注解关联起来
     2 @Retention(RetentionPolicy.RUNTIME)
     3 @Target(ElementType.TYPE)
     4 public @interface MyAnnotation {
     5     String value() default "java";
     6 }
     7 
     8 -------------------------------------------
     9 @Retention(RetentionPolicy.RUNTIME)
    10 @Target(ElementType.TYPE)
    11 public @interface MyAnnotations {
    12 
    13     MyAnnotation[] value();
    14 }

        这样一来,就可以使用重复注解了:

        

      2、类型注解

        JDK1.8之后,关于元注解@Target的参数类型ElementType枚举值多了两个:TYPE_PARAMETER,TYPE_USE

        

         Java 8之前, 注解只能是在声明的地方所使用, Java8开始, 注解可以应用在任何地方:

        ① ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中(如: 泛型声明) 。

        ② ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中

        声明注解,并添加 Target以上两个属性:

    1 @Inherited
    2 @Repeatable(MyAnnotations.class)
    3 @Retention(RetentionPolicy.RUNTIME)
    4 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
    5 public @interface MyAnnotation {
    6 
    7     String value() default "hello";
    8 }

        使用:案例一

     1 class Generic<@MyAnnotation T>{
     2 
     3     public void show() throws @MyAnnotation RuntimeException{
     4 
     5         ArrayList<@MyAnnotation String> list = new ArrayList<>();
     6 
     7         int num = (@MyAnnotation int) 10L;
     8     }
     9 
    10 }

       案例二:

     1 @MyAnnotation
     2 public class AnnotationTest<U> {
     3     @MyAnnotation
     4     private String name;
     5     public static void main(String[] args) {
     6         AnnotationTest<@MyAnnotation String> t = null;
     7         int a = (@MyAnnotation int) 2L;
     8         @MyAnnotation
     9         int b = 10;
    10     }
    11     public static <@MyAnnotation T> void method(T t) {
    12     }
    13     public static void test(@MyAnnotation String arg) throws @MyAnnotation Exception {
    14     }
    15 }
    16 @Target(ElementType.TYPE_USE)
    17 @interface MyAnnotation {
    18 }
  • 相关阅读:
    CSS实现背景透明,文字不透明(兼容各浏览器)
    JQUERY SCROLL PATH自定义滚动路径
    Truffle3.0集成NodeJS并完全跑通(附详细实例,可能的错误)
    truffle的调用nodeJs的问题
    Truffle基础篇-Truffle做什么的?怎么安装?
    以太坊智能合约开发笔记
    day02 智能合约
    remix无法安装的解决方案
    基于eth快速发行自己的数字货币
    remix-ide的三种使用方式
  • 原文地址:https://www.cnblogs.com/niujifei/p/14590474.html
Copyright © 2020-2023  润新知