zoukankan      html  css  js  c++  java
  • 注解

    一、注解的定义

    1.注解(Annotation),也叫元数据。它是jdk1.5后引入的一个新的特性。与类,接口,枚举是同一个层次。可以声明在类、字段、方法、局部变量、方法参数等的前面。注解也属于一种类型,有自己的语法

    1 @Target(ElementType.METHOD)
    2 @Retention(RetentionPolicy.RUNTIME)
    3 public @interface TestAnnotation {
    4 
    5 }

    如上所示,声明一个注解很简单,使用@interface声明TestAnnotation注解,并且使用两个java内置元注解(标识其他注解的注解)进行修饰。

    二、java中常见的注解

    1.元注解

    元注解专职负责注解其他注解,主要有下面四种:

    • @Target,主要用来约束注解可以使用的地方(如方法、类或字段)
    • @Retention,主要用来约束注解的生命周期,分别有三个值,源码级别(source),类文件级别(class)或者运行时级别(runtime),主要区别:RetentionPolicy.SOURCE:注解将被编译器丢弃(该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件里)RetentionPolicy.CLASS:注解在class文件中可用,但会被VM丢弃(该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中),请注意,当注解未定义Retention值时,默认值是CLASS,如Java内置注解,@Override、@Deprecated、@SuppressWarnning等。RetentionPolicy.RUNTIME:注解信息将在运行期(JVM)也保留,因此可以通过反射机制读取注解的信息(源码、class文件和执行的时候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。
    • @Document,将此注解包含在Jacadoc中
    • @Inherited,允许子类继承父类的注解

    2.标准注解

    • @Deprecated,Deprecated是弃用的意思,顾名思义这个注解用来标识过时的元素,例如过时的类,方法或者成员变量。
    • @Override,这可能是我们最熟悉的注解之一了,表示被注解的方法是复写了当前类父类的方法。
     1 public class Demo{
     2     @Deprecated
     3     public void test(){
     4         System.out.println("我已经被弃用");
     5     }
     6     @Override
     7     public boolean equals(Object obj) {
     8         return super.equals(obj);
     9     }
    10 }        
    • @SuppressWarnings,主要用来忽略各种警告用的。用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告,使用如下:
    public class Demo2 {
      @SuppressWarnings("deprecation")
        public void test2(){
            Demo demo = new Demo();
            demo.test();//当使用@SuppressWarnings("deprecation")后,警告消失
        }
    
    }    

    上例只是SuppressWarnings的一种,以上三种注解的详细使用说明可以参考源码。例如SuppressWarnnings注解的源码如下:

     1 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
     2 @Retention(RetentionPolicy.SOURCE)
     3 public @interface SuppressWarnings {
     4 String[] value();
     5 /*
     6 deprecation:使用了不赞成使用的类或方法时的警告;
     7 unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 
     8 fallthrough:当Switch 程序块直接通往下一种情况而没有 Break 时的警告;
     9 path:在类路径、源文件路径等中有不存在的路径时的警告; 
    10 serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告; 
    11 finally:任何 finally 子句不能正常完成时的警告; 
    12 all:关于以上所有情况的警告。
    13 */
    14 }

    3.注解元素

    1).注解元素可用的类型如下所示:

    所有的基本类型(int,float,boolean等等)

    • String
    • Class
    • enum
    • Annotation
    • 以上类型的数组

    2).注解元素的默认值限制

    编译器对注解元素的默认值有些过分的挑剔,元素不能有不确定的值,即元素必须要有默认值,要么在使用注解的时候提供元素的值。其次对于非基本类型的元素,无论是源码中声明时,或是注解接口中定义默认值的时候,不能以null作为其默认值。在注解的声明中,所有的元素都存在,并且具有其值,可以赋予空字符串或者负数,如下:

    1 @Target(ElementType.METHOD)
    2 @Retention(RetentionPolicy.RUNTIME)
    3 public @interface SimplDemo {
    4     public int id() default -1;
    5     public String description() default "";//元素的定义类似接口中方法的定义
    6     
    7 }

    注意:不能使用关键字extends来继承某个@interface.

    二、自定义注解的使用

    1.自定义注解的简单使用

    自定义一个注解TestAnnotation,主要用在方法上,首先定义一个注解,如下所示:

    1 @Target(ElementType.METHOD)
    2 @Retention(RetentionPolicy.RUNTIME)
    3 public @interface TestAnnotation {
    4     String name() ;
    5     String value();
    6 }

     定义注解的使用如下:

     1 public class Demo {
     2     @TestAnnotation(name = "test", value = "zz")
     3     public void test() {
     4         System.out.println("被注解方法执行完毕");
     5     }
     6 
     7     public void test2() {
     8 
     9     }
    10 
    11     public static void main(String[] args) {
    12         Demo demo = new Demo();
    13         Class<?> clz = demo.getClass();
    14         Method[] methods = clz.getDeclaredMethods();
    15         for (Method method : methods) {
    16             // 遍历Demo类定义的所有方法,如果方法被TestAnnotation注解,则执行方法,并获取注解的相关属性
    17             if (method.isAnnotationPresent(TestAnnotation.class)) {
    18                 method.setAccessible(true);
    19                 try {
    20                     method.invoke(demo, null);
    21                 } catch (Exception e) {
    22                     e.printStackTrace();
    23                 }
    24 
    25                 Annotation[] annotations = method.getAnnotations();
    26 
    27                 for (Annotation annotation : annotations) {
    28                     System.out.println(annotation);
    29                     if (annotation instanceof TestAnnotation) {
    30                         TestAnnotation testAnnotation = (TestAnnotation) annotation;
    31                         System.out.println(testAnnotation.name() + "--"
    32                                 + testAnnotation.value());
    33                     }
    34                 }
    35 
    36             }
    37         }
    38 
    39     }
    40 
    41 }

    结果输出:

    被注解方法执行完毕
    @com.demo.TestAnnotation(name=test, value=zz)
    test--zz

    注意:当TestAnnotation注解的保留策略是RetentionPolicy.CLASS和RetentionPolicy.SOURCE时,通过反射是获取不到注解信息的。

    通常对注解的使用,都是结合反射一起,如上通过反射和注解可以决定是都执行Demo对象的某个方法。上述例子也只是对注解的一个简单的使用,注解带来的好处和用法太多。

    主要有下面三方面:
    -提供信息给编译器:编译器可以利用注解来探测错误和警告信息
    -编译阶段时的处理:软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
    -运行时的处理: 某些注解可以在程序运行的时候接受代码的提取

    三、注解与反射

    有句话叫"纸上得来终觉浅,绝知此事要躬行",可能对注解还是一知半解,很多东西都是从不懂到懂,需要一个过程,可能这个过程是痛苦的,不过只要坚持,迟早会懂。等到了那一天反而会觉得很简单。通过实际的代码去理解理论知识,是最好的途径,特别是当在工作中使用了后就更有体会。下面这个例子是java编程思想中的一个经典的例子,能够帮助很好的理解注解和反射的关系。

     1 @Target(ElementType.TYPE)//用于注解类
     2 @Retention(RetentionPolicy.RUNTIME)
     3 public @interface DBTable {
     4     public String name() default "";
     5 }
     6 
     7 --------------------------------------------------------------
     8 @Target(ElementType.FIELD)
     9 @Retention(RetentionPolicy.RUNTIME)
    10 public @interface Constraints {
    11     boolean primaryKey() default false;
    12     boolean allowNull() default true;
    13     boolean unique() default false;
    14 }
    15 
    16 ---------------------------------------------------------------
    17 @Target(ElementType.FIELD)
    18 @Retention(RetentionPolicy.RUNTIME)
    19 public @interface SQLString {
    20     int value() default 0;
    21     String name() default "";
    22     Constraints constraints() default @Constraints;
    23 
    24 }
    25 
    26 ----------------------------------------------------------------
    27 @Target(ElementType.FIELD)
    28 @Retention(RetentionPolicy.RUNTIME)
    29 public @interface SQLInteger {
    30     String name() default "";
    31     Constraints constraints() default @Constraints;
    32 }

    应用上述自定义注解的类

     1 @DBTable(name="MEMBER")
     2 public class Member {
     3     @SQLString(30)
     4     String firstName;
     5     @SQLString(50)
     6     String lastName;
     7     @SQLInteger
     8     Integer age;
     9     @SQLString(value=30,constraints=@Constraints(primaryKey=true,allowNull=false,unique=true))
    10     String handle;
    11     static int memberCount;
    12     
    13     public String getHandle(){
    14         return handle;
    15     }
    16     public String getFirstName(){
    17         return firstName;
    18     }
    19     public String getLastName(){
    20         return lastName;
    21     }
    22     public String toString(){
    23         return handle;
    24     }
    25     public Integer getAge(){
    26         return age;
    27     }
    28 }

    实现处理器,利用反射和注解实现自动生产创建数据库表的SQL语句

     1 /**
     2  * 注解处理器
     3  *    
     4  */
     5 public class TableCreator {
     6     public static void main(String[] args)throws Exception {
     7         Class<?> clz = Class.forName("com.sun.lp.demo.Member");
     8         
     9         DBTable dbTable= clz.getAnnotation(DBTable.class);//获取DBTable注解
    10         if (dbTable==null) {
    11             System.out.println("no DBTable annotation in class Member");
    12             System.exit(0);
    13         }
    14         
    15         String tableName = dbTable.name();
    16         if(tableName.length()<1){
    17             tableName=clz.getName().toUpperCase();
    18         }
    19         List<String> list = new ArrayList<String>();
    20         String tableCreate =null;
    21         for(Field field:clz.getDeclaredFields()){
    22             String colName=null;
    23             Annotation [] annotations = field.getAnnotations();
    24             if(annotations.length<1)
    25                 continue;
    26             if(annotations[0] instanceof SQLInteger){
    27                 SQLInteger sInt = (SQLInteger) annotations[0];
    28                 if(sInt.name().length()<1)
    29                     colName = field.getName().toUpperCase();
    30                 else 
    31                     colName = sInt.name();
    32                 list.add(colName+" INT"+getConstraints(sInt.constraints()));
    33             }
    34             if(annotations[0] instanceof SQLString){
    35                 SQLString sString = (SQLString) annotations[0];
    36                 if(sString.name().length()<1)
    37                     colName = field.getName().toUpperCase();
    38                 else 
    39                     colName = sString.name();
    40                 list.add(colName+" VARCHAR("+sString.value()+")"+getConstraints(sString.constraints()));
    41             }
    42             
    43         }
    44         StringBuilder createCommand = new StringBuilder("CREATE TABLE "+tableName+"(");
    45         for(String colDef : list)
    46             createCommand.append("
       "+colDef+",");
    47         tableCreate = createCommand.substring(0,(createCommand.length()-1))+");";
    48         System.out.println(tableCreate);
    49     }
    50     
    51     private static String getConstraints(Constraints con){
    52         String constraints = "";
    53         if(!con.allowNull())
    54             constraints+=" NOT NULL";
    55         if(con.primaryKey())
    56             constraints+=" PRIMARY KEY";
    57         if(con.unique())
    58             constraints+=" UNIQUE";
    59         
    60         return constraints;
    61         
    62     }
    63 
    64 }

    结果输出:

    CREATE TABLE MEMBER(
       FIRSTNAME VARCHAR(30),
       LASTNAME VARCHAR(50),
       AGE INT,
       HANDLE VARCHAR(30) NOT NULL PRIMARY KEY UNIQUE);
  • 相关阅读:
    (Java) LeetCode 44. Wildcard Matching —— 通配符匹配
    (Java) LeetCode 30. Substring with Concatenation of All Words —— 与所有单词相关联的字串
    (Java) LeetCode 515. Find Largest Value in Each Tree Row —— 在每个树行中找最大值
    (Java) LeetCode 433. Minimum Genetic Mutation —— 最小基因变化
    (Java) LeetCode 413. Arithmetic Slices —— 等差数列划分
    (Java) LeetCode 289. Game of Life —— 生命游戏
    (Java) LeetCode 337. House Robber III —— 打家劫舍 III
    (Java) LeetCode 213. House Robber II —— 打家劫舍 II
    (Java) LeetCode 198. House Robber —— 打家劫舍
    (Java) LeetCode 152. Maximum Product Subarray —— 乘积最大子序列
  • 原文地址:https://www.cnblogs.com/liupiao/p/9273664.html
Copyright © 2011-2022 走看看