乾貨系列之java註解
前言
java反射和註解在java裏面很重要,但是很多人對這方面的知識理解不是很好,我來說說我自己對java反射和註解的理解,這兩塊內容本來應該出在一個博客文章裏面講解,但是由於我的java反射說的內容有點小多,然後我就分開將講解一下。
目錄
- 註解的概念
- 註解的類別
- 註解用法
- 通過反射獲取註解
- 反射註解一起使用拼寫SQL語句實戰演練
註解的概念
java註解:
比較官方的說法:
從JDK5開始,Java增加對元數據的支持,也就是註解,註解與註釋是有一定區別的,可以把註解理解爲代碼裏的特殊標記,這些標記可以在編譯,類加載,運行時被讀取,並執行相應的處理。通過註解開發人員可以在不改變原有代碼和邏輯的情況下在源代碼中嵌入補充信息。
註解,可以看作是對 一個 類/方法 的一個擴展的模版,每個 類/方法 按照註解類中的規則,來爲 類/方法 註解不同的參數,在用到的地方可以得到不同的 類/方法 中註解的各種參數與值。
說說我的理解
註解就是Annotation,相信不少人也和我之前一樣以爲和註釋一樣,是一段輔助性的文字,其實註解不是這樣的。註解與註釋的區別在於,註解可以實現程序的某些功能。
註解是不會影響java程序的運行,不會干擾程序代碼的運行。通俗來講,註解就像一個標籤,初學者需要知道他就像一個功能標籤,能實現一些功能就行了!入門了再慢慢深入理解。
看下面的例子你就能更好的理解註解了。
註解的類別
- java語言提供的註解
- 元註解
- 其他註解
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 全棧學習筆記)精彩美文每天爲你推送!