註解的基本盤點 -- 《Java編程思想》

      註解(元數據)爲咱們在代碼中添加信息提供了一種形式化的方法,使咱們能夠在以後的某一個時刻很是方便地使用這些數據。 ---《Java編程思想》java

      其實註解能夠理解爲一個工具類,只要使用了這個工具類後,主體類將會添加一些功能,就好像一個法師身邊多了一個小精靈。註解在必定程度上是把元數據和源代碼文件結合在一塊兒,而不是保存在外部文檔中這一個大的趨勢所催生的,不用去配置xml文件,不用去修改一些變量。之因此這麼說註解,有註解自己特性所決定的,只要在類、方法、變量等代碼的上方或者前方添加某個註解,那麼咱們將有這個註解的某個功能。數據庫

       不得不說,註解是Java SE5重要語言之一,能夠用來提供完整地描述程序所需的信息,存儲程序的額外有關的信息。註解能夠用來生成描述符文件,甚至或是新的類定義,有助於減輕編寫「樣板」代碼的負擔。編程

 

1、經常使用的Java內置的註解app


 

  • @Override,表示當前的的方法定義將覆蓋父類中的方法。因此咱們有時候以爲本身在子類中定義了一個和父類中存在的方法同樣的名字,就能夠本身覆蓋了父類的方法,卻沒有發現其實有可能沒有覆蓋成功,緣由有多是argument的個數和類型有誤差,這個時候用了@Override咱們就能夠知道是否覆蓋了,由於覆蓋成功,@Overrdie不會報錯,不然將會提示錯誤。
  • @Deprecated,將某個element給註釋爲過期危險的element,不鼓勵使用element,可是仍是可使用這個element。這個註解不少都是在類改造過程或者版本升級過程當中使用到,爲了兼顧舊版本,被引用的方法還能陪舊的版本使用。
    1     @Deprecated
    2     public static void sayHello(){
    3         System.out.println("Hello!!!");
    4     }
  • @SuppressWarnings,按照英文翻譯,壓制提醒,並且壓制提醒的將會壓制包含在壓制element裏面的element的,好比壓制提醒了一個類,那麼類裏面的方法也能夠被壓制到。下列中的一個System.runFinalizersOnExit(true),是一個過時的方法,那麼這個過時的方法被壓制提醒後將不會再被提醒了。
    1     @SuppressWarnings(value = { "deprecation" })
    2     public static void main(String[] args) {
    3         System.runFinalizersOnExit(true);
    4         
    5     }

 

2、定義註解框架


      除了咱們使用Java自己擁有的註解以外,咱們更多要本身去定義註解,以知足各類個性化的需求。在不少框架,Spring,Mybatis中,註解是被使用很是頻繁地一個Java工具。常見@Controller,@Component,@Service,@ResponseBody等等。下面就來看看這個定義中有方法和做用。ide

      定義註解重要有兩個元註解,@Target和@Retention,一個是註解做用的目標對象(FIELD,METHOD,CONSTRUCTOR),一個是註解做用的保持的一個生命週期(SOURCE,CLASS,RUNTIME),java源文件--》class文件--》內存中字節碼。工具

      例子一,用於密碼的校驗測試

  1. 定義註解,其中Target的目標是Method,用了ElementType.METHOD,而Retention則是RUNTIME,這個RUNTIME就是一個在編譯和運行時都有效的一個標誌。裏面的內容有一個區分的id和描述的description。
     1 package annotation;
     2 
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Retention;
     5 import java.lang.annotation.RetentionPolicy;
     6 import java.lang.annotation.Target;
     7 
     8 @Target(ElementType.METHOD)
     9 @Retention(RetentionPolicy.RUNTIME)
    10 public @interface UseCase {
    11 
    12     public int id();
    13     public String description() default "no description";
    14 }


  2. 應用註解,在PasswordUtils中應用了UseCase的註解。
     1 package annotation;
     2 
     3 import java.util.List;
     4 
     5 public class PasswordUtils {
     6 
     7     @UseCase(id =47 ,description = "passwords must contain at lease one numeric")
     8     public boolean validatePassword(String password){
     9         return (password.matches("\\w*\\d\\w*"));
    10     }
    11     
    12     @UseCase(id =48)
    13     public String encryptPassword(String password){
    14         return new StringBuilder(password).reverse().toString();
    15     }
    16     
    17     @UseCase(id = 49,description = "New password can't equel previously used ones")
    18     public boolean checkForNewPassword(List<String> prevPasswords, String password){
    19         return !prevPasswords.contains(password);
    20     }
    21 }
  3. 驗證效果,咱們會發現註解的不少部分都用到了反射機制中的方法,好比說是getDeclaredMethods獲得PassUtils的中的方法,而後再經過getAnnotation去獲得方法中的註解,再去根據註解中方法去拿到註解的值。

     1 package annotation;
     2 
     3 import java.lang.reflect.Method;
     4 import java.util.ArrayList;
     5 import java.util.Collections;
     6 import java.util.List;
     7 
     8 public class UseCaseTracker {
     9 
    10     public static void trackUseCases(List<Integer> useCases, Class<?> cl){
    11         for(Method m : cl.getDeclaredMethods()){
    12             UseCase uc = m.getAnnotation(UseCase.class);
    13             if(uc != null){
    14                 System.out.println("Found Use Case:" + uc.id() + " " + uc.description());
    15                 useCases.remove(new Integer(uc.id()));
    16             }
    17         }
    18         for(int i :useCases){
    19             System.out.println("Warning : Missing use Case -" + i);
    20         }
    21     }
    22     
    23     public static void main(String[] args) {
    24         List<Integer> useCases = new ArrayList<Integer>();
    25         Collections.addAll(useCases, 47,48,49,50);
    26         trackUseCases(useCases,PasswordUtils.class);
    27     }
    28 }
  4. 測試結果
    Found Use Case:47 passwords must contain at lease one numeric
    Found Use Case:48 no description
    Found Use Case:49 New password can't equel previously used ones
    Warning : Missing use Case -50

   

  下面咱們將進行一個定義註解在《Java編程思想》的一個很好的例子。目的是根據註解去生成一個SQL語句,這也是十分有用的。ui

  1. 定義一系列有關於生成數據庫的註解
     1 package annotation;
     2 
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Retention;
     5 import java.lang.annotation.RetentionPolicy;
     6 import java.lang.annotation.Target;
     7 
     8 @Target(ElementType.TYPE)
     9 @Retention(RetentionPolicy.RUNTIME)
    10 public @interface DBTable {
    11    
    12     public String name() default "";
    13 }
     1 package annotation;
     2 
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Retention;
     5 import java.lang.annotation.RetentionPolicy;
     6 import java.lang.annotation.Target;
     7 
     8 @Target(ElementType.FIELD)
     9 @Retention(RetentionPolicy.RUNTIME)
    10 public @interface Constraints {
    11 
    12     boolean primaryKey() default  false;
    13     boolean allowNull() default true;
    14     boolean unique() default false;
    15 }
     1 package annotation;
     2 
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Retention;
     5 import java.lang.annotation.RetentionPolicy;
     6 import java.lang.annotation.Target;
     7 
     8 @Target(ElementType.FIELD)
     9 @Retention(RetentionPolicy.RUNTIME)
    10 public @interface SQLString {
    11  
    12     int value() default 0;
    13     String name() default "";
    14     Constraints constraints() default @Constraints;
    15 }
     1 package annotation;
     2 
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Retention;
     5 import java.lang.annotation.RetentionPolicy;
     6 import java.lang.annotation.Target;
     7 
     8 @Target(ElementType.FIELD)
     9 @Retention(RetentionPolicy.RUNTIME)
    10 public @interface SQLInteger {
    11 
    12     String name() default "";
    13     Constraints constraints() default @Constraints;
    14 }

     

  2. 寫出一個做用的類Member,而後在將咱們上面所定義的註解應用到該註解中。
    package annotation;
    
    @DBTable(name ="MEMBER")
    public class Member {
    
        @SQLString(30) String firstName;
        @SQLString(50) String lastName;
        @SQLInteger Integer age;
        @SQLString(value =30, constraints = @Constraints(primaryKey = true))
        String handle;
        static int memberCount;
        public String getHandle(){return handle;}
        public String getFirstName(){return firstName;}
        public String getlastName(){return lastName;}
        public String toString(){return handle;}
        public Integer getAge(){return age;}
    
    }

     

  3. 接下來,進行一個TableCreator,表格Sql的生成。運用了getAnnotation,getDeclaredFields,getDeclaredAnnotations等有關於反射的一系列的方法,去獲得被註解應用的類中的各項屬性的中值。
     1 package annotation;
     2 
     3 import java.lang.annotation.Annotation;
     4 import java.lang.reflect.Field;
     5 import java.util.ArrayList;
     6 import java.util.List;
     7 
     8 public class TableCreator {
     9 
    10     public static void main(String[] args) throws Exception {
    11         getSQL(new String[]{"annotation.Member"});
    12     }
    13 
    14     public static void getSQL(String[] args) throws ClassNotFoundException {
    15         if(args.length <1){
    16             System.out.println("arguments : annotated classes");
    17             System.exit(0);
    18         }
    19         for(String className :args){
    20             Class<?> cl = Class.forName(className);
    21             DBTable dbTable = cl.getAnnotation(DBTable.class);
    22             if(dbTable == null){
    23                 System.out.println("No DBTable annotation in class " + className);
    24                 continue;
    25             }
    26             String tableName = dbTable.name();
    27             //If the name is empty ,use the Class name;
    28             if(tableName.length() <1){
    29                 tableName = cl.getName().toUpperCase();
    30             }
    31             List<String> columnDefs = new ArrayList<String>();
    32             for(Field field : cl.getDeclaredFields()){
    33                 String columnName = null;
    34                 Annotation[] anns = field.getDeclaredAnnotations();
    35                 if(anns.length <1){
    36                     continue;//not a db table column
    37                 }
    38                 if(anns[0] instanceof SQLInteger){
    39                     SQLInteger sInt = (SQLInteger) anns[0];
    40                     //user field name if name not specified
    41                     if(sInt.name().length() < 1)
    42                         columnName = field.getName().toUpperCase();
    43                     else
    44                         columnName= sInt.name();
    45                     columnDefs.add(columnName + " INT" + getConstraints(sInt.constraints()));
    46                 }
    47                 if(anns[0] instanceof SQLString){
    48                     SQLString sString = (SQLString) anns[0];
    49                     //use field name if name not specified
    50                     if(sString.name().length() <1){
    51                         columnName = field.getName().toUpperCase();
    52                     }else{
    53                         columnName = sString.name();
    54                     }
    55                     columnDefs.add(columnName + " VARCHAR(" +sString.value() + ")"
    56                             +getConstraints(sString.constraints()));
    57                 }
    58                 StringBuilder createCommand = new StringBuilder(
    59                         "CREATE TABLE " + tableName +"(");
    60                 for(String columnDef : columnDefs)
    61                     createCommand.append("\n   " + columnDef + ",");
    62                 //Remove trailing comma
    63                 String tableCreate = createCommand.substring(0,createCommand.length() -1) +");";
    64                 System.out.println("Table Creation SQL for " + className + " is :\n" + tableCreate);;
    65             } 
    66             
    67         }
    68     }
    69 
    70     private static String getConstraints(Constraints con) {
    71         // TODO Auto-generated method stub
    72         String constraints = "";
    73         if(!con.allowNull())
    74             constraints += "NOT NULL";
    75         if(con.primaryKey())
    76             constraints += "PRIMARY KEY";
    77         if(con.unique())
    78             constraints += "UNIQUE";
    79         return constraints;
    80     }
    81 }

     

  4. 運行的結果
    Table Creation SQL for annotation.Member is :
    CREATE TABLE MEMBER(
       FIRSTNAME VARCHAR(30));
    Table Creation SQL for annotation.Member is :
    CREATE TABLE MEMBER(
       FIRSTNAME VARCHAR(30),
       LASTNAME VARCHAR(50));
    Table Creation SQL for annotation.Member is :
    CREATE TABLE MEMBER(
       FIRSTNAME VARCHAR(30),
       LASTNAME VARCHAR(50),
       AGE INT);
    Table Creation SQL for annotation.Member is :
    CREATE TABLE MEMBER(
       FIRSTNAME VARCHAR(30),
       LASTNAME VARCHAR(50),
       AGE INT,
       HANDLE VARCHAR(30)PRIMARY KEY);

     

3、現階段中不少在運用到註解的例子spa


 

  • JUnit
  • Spring
  • SpringMVC
  • MyBatis
  • Hibernate
相關文章
相關標籤/搜索