天天看點

幹貨系列之java注解

幹貨系列之java注解

前言

java反射和注解在java裡面很重要,但是很多人對這方面的知識了解不是很好,我來說說我自己對java反射和注解的了解,這兩塊内容本來應該出在一個部落格文章裡面講解,但是由于我的java反射說的内容有點小多,然後我就分開将講解一下。

目錄

  1. 注解的概念
  2. 注解的類别
  3. 注解用法
  4. 通過反射擷取注解
  5. 反射注解一起使用拼寫SQL語句實戰演練

注解的概念

java注解:

比較官方的說法:

從JDK5開始,Java增加對中繼資料的支援,也就是注解,注解與注釋是有一定差別的,可以把注解了解為代碼裡的特殊标記,這些标記可以在編譯,類加載,運作時被讀取,并執行相應的處理。通過注解開發人員可以在不改變原有代碼和邏輯的情況下在源代碼中嵌入補充資訊。

注解,可以看作是對 一個 類/方法 的一個擴充的模版,每個 類/方法 按照注解類中的規則,來為 類/方法 注解不同的參數,在用到的地方可以得到不同的 類/方法 中注解的各種參數與值。

說說我的了解

注解就是Annotation,相信不少人也和我之前一樣以為和注釋一樣,是一段輔助性的文字,其實注解不是這樣的。注解與注釋的差別在于,注解可以實作程式的某些功能。

注解是不會影響java程式的運作,不會幹擾程式代碼的運作。通俗來講,注解就像一個标簽,初學者需要知道他就像一個功能标簽,能實作一些功能就行了!入門了再慢慢深入了解。

看下面的例子你就能更好的了解注解了。

注解的類别

  1. java語言提供的注解
  2. 元注解
  3. 其他注解

java語言提供的注解

1.Override

學過java你就知道,你肯定見過這種

@Override
public Object clone() throws CloneNotSupportedException {}
           

沒錯,@Override就是一個java提供的注解。當你要重寫父類的方法是需要用到這個注解。

2.@Deprecated

這個注解你能看到的時間比較少,但是你應該見過類似的,編譯一個java程式時,編譯器可能會提示你你使用了一個過時的方法(idea會),或者過時的類,過時的成員變量。

3.@SuppressWarnings

這個注解的意思是:阻止編譯器的警告,上一個注解說到@Deprecated會提示你使用過時方法等的一個警告,當你使用了這個注解之後就不會有這種提示了!這個注解需要一個參數,參數都是提前設計好了的。

參數如下

  • deprecation 使用了過時的類或方法的警告
  • unchecked 執行了未檢查的轉換時的警告,如使用集合時未指定泛型
  • fallthrough :當在switch語句使用時發生case穿透
  • path 在類路徑,源檔案路徑等中有不存在路徑的警告
  • serial 當在可序列化的類上缺少serialVersionUID定義時的警告
  • finally 任何finally子句不能完成時的警告
  • all 關于以上所有情況的警告

元注解

所謂元注解就是注解的注解,雖然說這些注解也是java語言提供的,但是他不同于上面說的哪幾種注解,上面的幾種注解也是由元注解組成的。他們的源代碼裡面包含了元注解。

元注解有哪些呢?

- @Target:注解的作用目标
- @Retention:注解的生命周期
- @Documented:注解是否應當被包含在 JavaDoc 文檔中
- @Inherited:是否允許子類繼承該注解
           

這4個值java8之前的元注解,在java8又新增了一個

@Repeatable 元注解,表示被修飾的注解可以用在同一個聲明式或者類型加上多個相同的注解(包含不同的屬性值)

我們詳細說一下這些注解都是什麼意思

1.@Target 注解的作用目标

具體的作用目标有以下幾個

- ElementType.TYPE:允許被修飾的注解作用在類、接口和枚舉上

- ElementType.FIELD:允許作用在屬性字段上

- ElementType.METHOD:允許作用在方法上

- ElementType.PARAMETER:允許作用在方法參數上

- ElementType.CONSTRUCTOR:允許作用在構造器上

- ElementType.LOCAL_VARIABLE:允許作用在局部變量上

- ElementType.ANNOTATION_TYPE:允許作用在注解上

- ElementType.PACKAGE:允許作用在包上

以上都是這個注解的參數

可能有人會問作用目标是什麼?就是說我聲明的這個注解可以用在那個地方,比如說@Override,是不是隻能用在重寫的方法上面。如果你學了springboot的話,裡面的很多注解都是可以使用在類上面也可以使用在方法上面。

2.@Retention 注解的生命周期

什麼意思?注解本身是不會影響正常邏輯程式的運作的,然後這個注解的生命周期指的是我聲明的這個注解會保留到什麼階段,具體的參數如下:

- RetentionPolicy.SOURCE:目前注解編譯期可見,不會寫入 class 檔案,會被編譯器丢棄
- RetentionPolicy.CLASS:類加載階段丢棄,會寫入 class 檔案,會被java虛拟機丢棄
- RetentionPolicy.RUNTIME:永久儲存,可以反射擷取到對應的注解
           

3.@Documented 注解是否應當被包含在 JavaDoc 文檔中

這個倒沒有什麼好說的,就是标注被修飾這個注解包含在JavaDoc文檔中。

4.@Inherited 是否允許子類繼承該注解

簡單點說,子類繼承父類時,如果父類的注解有@Inherited辨別的注解,子類繼承過來的時候也會自動繼承@Inherited辨別的注解。

但是在接口繼承的時候,子類不會繼承任何@Inherited辨別的注解。

5.@Repeatable

在需要對同一種注解多次使用時,往往需要借助@Repeatable。比如說,現在有一篇文章,這篇文章需要添加多個标簽,這些标簽就相當于注解,但是這個标簽隻是内容不同,這時候就需要使用到這個注解了。

其他注解

所謂的其他注解就是第三方注解,比如說很火的springboot,它提供了很多的注解,可以替代一些配置檔案,告訴這個架構有這個注解是需要提供哪些功能。比如說@Controller,@RequestMapping,@Service等。

注解用法

講了半天,可能你還是一臉懵逼,你隻講概念,怎麼用?

下面就來介紹這個注解怎麼用,主要是講解注解的聲明用法。

1.注解聲明

public @interface Entity {

}
           

這個和聲明接口很類似,隻是在前面多了一個@

具體怎麼用,我們用一個例子來講解

@Target(ElementType.TYPE)//允許聲明的注解修飾在接口,類,枚舉上面
@Retention(RetentionPolicy.RUNTIME)//代碼運作期間一直儲存注解,可以通過反射擷取
public @interface Entity {
	//表名,注解的參數,預設為空
	public String tableName() default "";
	//中文名稱
	public String cnName() default "";

}
           

解釋一下注解的參數聲明

第一個參數定義參數為String類型,設定default 預設值,表示這個不是必須的,在使用注解的時候沒有填寫這個參數不會報錯,他會使用預設值。

聲明好注解之後,我們将這些注解運用到一個實體類上面。

再來一個聲明的作用在屬性上面的注解。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    //屬性的名稱
    public String fieldName() default "";
    //屬性的屬性中文名稱
    public String fieldCnName() default "";
    //屬性的類型
    public String Type() default "String";
}
           

然後我們将這兩個注解運用到實體類Student上面。

@Entity(tableName = "student",cnName = "學生表")
public class Student {
    @Column(fieldCnName = "姓名",fieldName ="name")
    private String name;
    @Column(fieldCnName = "年齡",fieldName = "age",Type = "Integer")
    private Integer age;
    @Column(fieldCnName = "性别",fieldName = "sex")
    private String sex;
}
           

set,get方法沒有貼上來。

具體的用法就是這樣了。然後我們說說注解與反射的關系,怎麼用反射擷取注解。

通過反射擷取注解

不會反射的請看上一篇文章,8000字為你講懂反射,然後再回來看這篇注解的文章。

上代碼直接

//擷取Class類
    Class clazz = Student.class;

    //擷取類上面的注解
    Entity entity = (Entity) clazz.getAnnotation(Entity.class);
    System.out.println(entity.cnName()+entity.tableName());

    //擷取所有該類聲明的屬性
    Field fields[] = clazz.getDeclaredFields();

    for (Field field:fields){
        //擷取對應屬性上面的注解
        Column column = field.getAnnotation(Column.class);
        System.out.println(column.fieldCnName());
    }
           

這個運作結果是

學生表student
姓名
年齡
性别
           

很簡單是不是。懂了嗎?懂了的話關注走一波?精彩美文每天為你推送,喜歡手機看文章的還可以(wx search 全棧學習筆記)!

反射注解一起使用拼寫SQL語句實戰演練

其實這一部分你懂反射和注解就會了,通過反射和注解你可以實作一個簡單的萬能的增删改查。貼個新增的SQL語句代碼吧!

//insert into student_test(student_id,student_name,student_sex) values (1,"Jack","男")
    StringBuilder sql = new StringBuilder();
    Class clazz = object.getClass();
    sql.append("insert into ");
    //擷取類上面的注解
    Entity entity = (Entity) clazz.getAnnotation(Entity.class);
    sql.append(entity.tableName());

    sql.append("(");
    Field[] fields = clazz.getDeclaredFields();
    for(Field field:fields){
        sql.append(field.getAnnotation(Column.class).fieldName()).append(",");
    }
    sql.deleteCharAt(sql.length()-1);
    sql.append(")");
    sql.append(" values (");
    for(Field field:fields){
        field.setAccessible(true);
        Object value = field.get(object);
        if(value.getClass().equals(String.class)){
            sql.append("\"").append(value).append("\"").append(",");
        }else {
            sql.append(value).append(",");
        }
    }
    sql.deleteCharAt(sql.length()-1);
    sql.append(")");
    System.out.println(sql.toString());
    return sql.toString();
           

結語:覺得文章不錯的,帶上原文連結,歡迎轉發,如果你發現文章中有錯誤可以評論或者私信我,及時修改!(wx search 全棧學習筆記)精彩美文每天為你推送!