java注解的使用


java中注解的使用

1.說再前面

使用注解開發的好處

1.使代碼更加干凈易讀,易於維護修改。比如,以前使用spring的開發,都是基於xml文件實現了統一的配置管理,但是缺點也是顯而易見的,就是隨着項目的越來越大,xml文件會變得越來越復雜,維護成本也會越來越高。使用注解就可以提供更大的便捷性,易於維護修改。

2 可以實現代碼的類型檢查,特別是在編譯器的角度實現一些類型檢查,比如預檢查(@Override)和抑制警告(@SuppressWarnings)等。

3 自定義注解,作為額外信息的載體,存儲有關程序的額外信息

2 注解的分類以及使用

​ Java注解是附加在代碼中的一些元信息,用於編譯和運行時進行解析和使用,起到說明、配置的功能。

注解不會影響代碼的實際邏輯,僅僅起到輔助性的作用。包含在java.lang.annotation包中。注解的定義類似於接口的定義,使用@interface來定義,定義一個方法即為注解類型定義了一個元素,方法的聲明不允許有參數或throw語句,返回值類型被限定為原始數據類型、字符串String、Class、enums、注解類型,或前面這些的數組,方法可以有默認值。注解並不直接影響代碼的語義,但是他可以被看做是程序的工具或者類庫。它會反過來對正在運行的程序語義有所影響。注解可以從源文件、class文件或者在運行時通過反射機制多種方式被讀取。

一般來說,注解一般分為三種類型: 元注解,標准注解,自定義注解

2.1 元注解

元注解是專職負責注解其他注解,主要是標明該注解的使用范圍,生效范圍。我們是不能改變它的,只能用它來定義我們自定義的注解。

包括 @Retention @Target @Document @Inherited四種。(java.lang.annotation中提供,為注釋類型)。

注解 說明
@Target 定義注解的作用目標,也就是可以定義注解具體作用在類上,方法上,還是變量上
@Retention 定義注解的保留策略。RetentionPolicy.SOURCE:注解僅存在於源碼中,在class字節碼文件中不包含;RetentionPolicy.CLASS:默認的保留策略,注解會在class字節碼文件中存在,但運行時無法獲得;RetentionPolicy.RUNTIME:注解會在class字節碼文件中存在,在運行時可以通過反射獲取到。
@Document 說明該注解將被包含在javadoc中
@Inherited 說明子類可以繼承父類中的該注解

Target類型主要依賴於ElementType這個類型,具體的類型如下:

Target類型 說明
ElementType.TYPE 接口、類、枚舉、注解
ElementType.FIELD 字段、枚舉的常量
ElementType.METHOD 方法
ElementType.PARAMETER 方法參數
ElementType.CONSTRUCTOR 構造函數
ElementType.LOCAL_VARIABLE 局部變量
ElementType.ANNOTATION_TYPE 注解
ElementType.PACKAGE

2.2 標准注解

Java標准注解提供了三個,定義在java.lang中的注解,我認為這三個注解的作用更多的是一種注釋

  • @Override 表示當前方法覆蓋父類中的方法。

  • @Deprecated 標記一個元素為已過期,避免使用

支持的元素類型為:CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE

  • @SuppressWarnings 不輸出對應的編譯警告

    一個簡單的使用demo:

    @SuppressWarnings(value = {"unused", "rawtypes"})
    public class Children  extends Parent{
        @Override
        public void work() {
            System.out.println("我是一個被重寫的方法");
        }
    
        @Deprecated
        public void play(){
            System.out.println("這個方法不推薦使用了");
        }
    }
    

2.3 自定義注解實現一個sql語句的拼接

需要注意的方面:注解的定義類似於接口的定義,使用@interface來定義,定義一個方法即為注解類型定義了一個元素,方法的聲明不允許有參數或throw語句,返回值類型被限定為原始數據類型、字符串String、Class、enums、注解類型,或前面這些的數組,方法可以有默認值。

自定義注解一般可以分為三步: 定義注解,使用注解,讀取注解

定義注解

@Target(ElementType.TYPE) //注解加載類上
@Retention(RetentionPolicy.RUNTIME) // 運行時讀取注解

public @interface Table {
    String value(); 
}


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public@interface UserFiled {
    String name();
    String type();
    int length();
}

使用注解

// 將自定義的注解加在用戶上,實現一個表的映射
@Table(value = "user_table")
public class User {

    @UserFiled(name = "user_id",type = "int",length = 8)
    private int userId;

    @UserFiled(name = "user_name",type = "varchar",length = 16)
    private String userName;

    @UserFiled(name = "password",type = "varchar",length = 16)
    private String password;

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

讀取注解的內容

/**
 * 讀取注解中的值
 */
public class GetUser {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class userClass = Class.forName("annocation.blog.User");

        // 讀取類上的注解
        Table table = (Table) userClass.getAnnotation(Table.class);
        System.out.println(table.value());

        // 讀取屬性上注解
        Field userId = userClass.getDeclaredField("userId");
        UserFiled userFiledId = userId.getAnnotation(UserFiled.class);
        System.out.println(userFiledId.length() + "----" + userFiledId.type() + "-----" + userFiledId.name());

        Field userName = userClass.getDeclaredField("userName");
        UserFiled userFiledName = userName.getAnnotation(UserFiled.class);
        System.out.println(userFiledName.length()+"----"+userFiledName.type()+"----"+userFiledName.name());

        Field password = userClass.getDeclaredField("password");
        UserFiled userFiledPassword = password.getAnnotation(UserFiled.class);
        System.out.println(userFiledPassword.name() + "-----" + userFiledPassword.type() + "-----" + userFiledPassword.length());

        // 拼接一個sql語句
        String name = "chenwei";
        String sql ="select * from" + table.value()+"where"+userFiledName.name()+"="+name;
    }
}

結果:

user_table
user_id----int-----8
user_name----varchar----16
password-----varchar-----16

自定義注解的實現過程:

1,定義注解

2,使用注解,根據自己定義的注解來達到一些目的,本例中,就是使用注解來完成數據庫表和實體類的映射關系

3 讀取注解的內容,也是比較重要的一部分,核心還是利用了反射的思想,得到使用注解的這個類,根據類中的getAnnotion的方法得到定義的注解,獲得注解上的值。

3 注解的實現的原理

注解的實現的原理很大的一部分是基於反射實現。

​ 反射可以獲取到Class對象,進而獲取到Constructor、Field、Method等實例,點開源碼結構發現Class、Constructor、Field、Method等均實現了AnnotatedElement接口,AnnotatedElement接口的方法如下

// 判斷該元素是否包含指定注解,包含則返回true
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
    
// 返回該元素上對應的注解,如果沒有返回null
<T extends Annotation> T getAnnotation(Class<T> annotationClass);

// 返回該元素上的所有注解,如果沒有任何注解則返回一個空數組
Annotation[] getAnnotations();

// 返回指定類型的注解,如果沒有返回空數組
T[] getAnnotationsByType(Class<T> annotationClass)
    
// 返回指定類型的注解,如果沒有返回空數組,只包含直接標注的注解,不包含inherited的注解
T getDeclaredAnnotation(Class<T> annotationClass)
    
// 返回指定類型的注解,如果沒有返回空數組,只包含直接標注的注解,不包含inherited的注解
T[] getDeclaredAnnotationsByType
    
// 返回該元素上的所有注解,如果沒有任何注解則返回一個空數組,只包含直接標注的注解,不包含inherited的注解
Annotation[] getDeclaredAnnotations();

通過一個實例再次說明一下注解的使用過程:

定義注解

@Documented
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotaion {
    String getValue() default "this is myAnntaion";
    int order() default 0;
}

使用注解

@MyAnnotaion(getValue = "annotation on class")
public class Demo {

    @MyAnnotaion(getValue = "annotation on filed")
    public String name;

    @MyAnnotaion(getValue = "annotation on method")
    public void hello(){
    }

    @MyAnnotaion
    public void defaultMethod(){

    }
}

利用反射讀取注解中的值。

public class TestDemo {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
        /**
         * 獲取類上的注解
         */
        Class<Demo> demoClass = Demo.class;
        Annotation[] annotaion = demoClass.getAnnotations();
        printAnnotation(annotaion);

        /**
         * 讀取成員變量上的注解
         */
        Field name = demoClass.getField("name");
        Annotation[] getOnFiled = name.getAnnotations();
        printAnnotation(getOnFiled);

        /**
         * 讀取方法上的注解
         */
        Method hello = demoClass.getMethod("hello", null);
        MyAnnotaion onMethod = hello.getAnnotation(MyAnnotaion.class);
        System.out.println(onMethod.getValue());

        /**
         * 獲取默認方法上的注解
         */
        Method defaultMethod = demoClass.getMethod("defaultMethod", null);
        MyAnnotaion onDefaultMethod = defaultMethod.getAnnotation(MyAnnotaion.class);
        System.out.println(onDefaultMethod.getValue());

    }

    public static void printAnnotation(Annotation... annotations) {
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
    }
}

運行結果

@annocation.MyAnnotaion(getValue=annotation on class, order=0)
@annocation.MyAnnotaion(getValue=annotation on filed, order=0)
annotation on method
this is myAnntaion

參考資料:

http://blog.kimzing.com/java/Java注解入門到精通-學這一篇就夠了/

《java編程思想》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM