注解基本應用

注解:

注解目前非常的流行,很多主流框架都支持注解,而且自己編寫代碼的時候也會盡量的去用注解,既方便,也讓代碼更加簡潔。

注解雜談:


Annontation是Java5開始引入的新特征,中文名稱叫注解。它提供了一種安全的類似注釋的機制,用來將任何的信息或元數(shù)據(jù)(metadata)與程序元素(類、方法、成員變量等)進行關(guān)聯(lián)。為程序的元素(類、方法、成員變量)加上更直觀更明了的說明,這些說明信息是與程序的業(yè)務邏輯無關(guān),并且供指定的工具或框架使用。Annontation像一種修飾符一樣,應用于包、類型、構(gòu)造方法、方法、成員變量、參數(shù)及本地變量的聲明語句中。
Java注解是附加在代碼中的一些元信息,用于一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。注解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用。包含在 java.lang.annotation 包中。


你常見到的這個東東,還記得嗎?

  @Override
    public String toString() {
        return "Test{}";
    }

@Override 就是我們接下來要說的注解了,這個注解用來標記子類重寫的父類中的方法,如果父類中沒有該方法,則編譯器就會報錯提示開發(fā)者

常見的元注解

@Documented –注解是否將包含在JavaDoc中
@Retention –什么時候使用該注解
@Target? –注解用于什么地方
@Inherited – 是否允許子類繼承該注解

注解-簡而言之:解釋某個方法或者字段或者類,予以標記,讓代碼更易閱讀。


使用Annotation之前(甚至在使用之后),XML被廣泛的應用于描述元數(shù)據(jù)。不知何時開始一些應用開發(fā)人員和架構(gòu)師發(fā)現(xiàn)XML的維護越來越糟糕了。他們希望使用一些和代碼緊耦合的東西,而不是像XML那樣和代碼是松耦合的(在某些情況下甚至是完全分離的)代碼描述。
假如你想為應用設置很多的常量或參數(shù),這種情況下,XML是一個很好的選擇,因為它不會同特定的代碼相連。如果你想把某個方法聲明為服務,那么使用Annotation會更好一些,因為這種情況下需要注解和方法緊密耦合起來,開發(fā)人員也必須認識到這點
另一個很重要的因素是Annotation定義了一種標準的描述元數(shù)據(jù)的方式。在這之前,開發(fā)人員通常使用他們自己的方式定義元數(shù)據(jù)。例如,使用標記interfaces,注釋,transient關(guān)鍵字等等。每個程序員按照自己的方式定義元數(shù)據(jù),而不像Annotation這種標準的方式。
目前,許多框架將XML和Annotation兩種方式結(jié)合使用,平衡兩者之間的利弊。
簡單來說:本來可能需要很多配置文件,需要很多邏輯才能實現(xiàn)的內(nèi)容,就可以使用一個或者多個注解來替代,這樣就使得編程更加簡潔,代碼更加清晰。


注解的用處:
1、生成文檔。這是最常見的,也是java 最早提供的注解。常用的有@param @return 等
2、跟蹤代碼依賴性,實現(xiàn)替代配置文件功能。比如Dagger 2依賴注入,未來java開發(fā),將大量注解配置,具有很大用處;
3、在編譯時進行格式檢查。如@override 放在方法前,如果你這個方法并不是覆蓋了超類方法,則編譯時就能檢查出。
注解的原理:
  注解本質(zhì)是一個繼承了Annotation的特殊接口,其具體實現(xiàn)類是Java運行時生成的動態(tài)代理類。而我們通過反射獲取注解時,返回的是Java運行時生成的動態(tài)代理對象$Proxy1。通過代理對象調(diào)用自定義注解(接口)的方法,會最終調(diào)用AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中索引出對應的值。而memberValues的來源是Java常量池。


簡單用下注解,隨機獻上老棧的DEMO

創(chuàng)建自定義注解類:

import com.sun.istack.internal.Interned;
import java.lang.annotation.*;
//該注解使用范圍在方法上
@Target(ElementType.METHOD)
//該注解用來指定編譯的時期
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
    //配置幾個解釋的字段,如果該字段有默認值,可以使用default指定
    public int id ();
    public String description() default "test";
}

注解:根據(jù)需要設置字段,有時候也不需要設置,僅僅起到標記作用,類似于空接口

接下來:創(chuàng)建一個自定義的類

public class PasswordUtils {
     @UseCase(id = 47, description ="密碼描述")
     public boolean validatePassword(String password) {
         return (password.matches("\\w*\\d\\w*"));
     }
     @UseCase(id = 50)
     public String encryptPassword(String password) {
         return new StringBuilder(password).reverse().toString();
     }
}

這樣在測試類中,對于進行注解標記的字段,就可以通過java 反射,獲取到二進制文件,從而獲取在方法、字段、類、或者接口頂部的注解,而根據(jù)自定義注解的內(nèi)容,便可以根據(jù)數(shù)據(jù)的含義進行數(shù)據(jù)操作,簡化代碼,或者根據(jù)某個注解某個特殊的值來進行業(yè)務處理,很多框架也多有類似設計。

測試類:

    public static void main(String[] args) {
        List<Integer> useCases = new ArrayList<Integer>();
        Collections.addAll(useCases, 47, 48, 49, 50);
        trackUseCases(useCases, PasswordUtils.class);
    }

    public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
        for (Method m : cl.getDeclaredMethods()) {
            UseCase uc = m.getAnnotation(UseCase.class);
            if (uc != null) {
                System.out.println("Found Use Case:" + uc.id() + " "
                        + uc.description());
                useCases.remove(new Integer(uc.id()));
            }
        }
        for (int i : useCases) {
            System.out.println("Warning: Missing use case-" + i);
        }
    }

注解學習要點:

1.注解的元注解。
2.注解的屬性。
3.注解主要給編譯器及工具類型的軟件用的。
4.注解的提取需要借助于 Java 的反射技術(shù),反射比較慢,所以注解使用時也需要謹慎計較時間成本。


待續(xù)。。。

追加一個補充例子: 對他人寫的代碼檢測,注解樣例:

注解樣例

package ceshi;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Jiecha {

}

*** 檢測類***

package ceshi;
import ceshi.Jiecha;


public class NoBug {

    @Jiecha
    public void suanShu(){
        System.out.println("1234567890");
    }
    @Jiecha
    public void jiafa(){
        System.out.println("1+1="+1+1);
    }
    @Jiecha
    public void jiefa(){
        System.out.println("1-1="+(1-1));
    }
    @Jiecha
    public void chengfa(){
        System.out.println("3 x 5="+ 3*5);
    }
    @Jiecha
    public void chufa(){
        System.out.println("6 / 0="+ 6 / 0);
    }

    public void ziwojieshao(){
        System.out.println("我寫的程序沒有 bug!");
    }

}
檢測執(zhí)行:
package ceshi;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;



public class TestTool {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        NoBug testobj = new NoBug();

        Class clazz = testobj.getClass();

        Method[] method = clazz.getDeclaredMethods();
        //用來記錄測試產(chǎn)生的 log 信息
        StringBuilder log = new StringBuilder();
        // 記錄異常的次數(shù)
        int errornum = 0;

        for ( Method m: method ) {
            // 只有被 @Jiecha 標注過的方法才進行測試
            if ( m.isAnnotationPresent( Jiecha.class )) {
                try {
                    m.setAccessible(true);
                    m.invoke(testobj, null);

                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    //e.printStackTrace();
                    errornum++;
                    log.append(m.getName());
                    log.append(" ");
                    log.append("has error:");
                    log.append("\n\r  caused by ");
                    //記錄測試過程中,發(fā)生的異常的名稱
                    log.append(e.getCause().getClass().getSimpleName());
                    log.append("\n\r");
                    //記錄測試過程中,發(fā)生的異常的具體信息
                    log.append(e.getCause().getMessage());
                    log.append("\n\r");
                } 
            }
        }


        log.append(clazz.getSimpleName());
        log.append(" has  ");
        log.append(errornum);
        log.append(" error.");

        // 生成測試報告
        System.out.println(log.toString());

    }

}

結(jié)合反射, 注解效力。


如果大家有時間也可以研究下Hibernate的框架,通過注解是如何生成sql語句的呢? 日后有時間會更新該Demo,希望大家支持關(guān)注,過幾天手寫Hibernate注解Demo。。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容