注解的初步了解
-
是從JDK5.0開始引入的新技術Annotation
-
作用Annotation
- 注解不是程式本身,可以對程式作出解釋。(這一點和注釋沒有什麼差別)
- 注解可以被其他程式(比如:編譯器等)讀取。(注解資訊處理流程,是注解和注釋的重大差別。如果沒有注解資訊處理流程,則注解毫無意義)
-
的格式Annotation
- 注解是以"@注釋名"在代碼中存在的,還可以添加一些參數值,例如
@SuppressWarnings(value = "unchecked")
- 注解是以"@注釋名"在代碼中存在的,還可以添加一些參數值,例如
-
在哪裡使用?Annotation
- 可以附加在
,package
,class
,method
等上面,相當于給他們添加了額外的輔助資訊,我們可以通過反射機制程式設計實作對源資料的通路。field
- 可以附加在
一些内置注解
-
@Override
定義在
java.lang.Override
中,此注解用于修飾一個方法,表示一個方法聲明打算重寫超類中的另一個方法聲明。
例如重寫
Object
類中的
toString()
方法
如果
@Override
标注的方法不是父類的方法,就會報錯
-
@Deprecated
定義在
java.lang.Deprecated
中,此注釋可用于修飾方法、屬性、類,表示不鼓勵程式員使用這樣的元素,通常是因為它很危險或存在更好的選擇
-
@SupprerssWarnings
定義在
java.lang.SupressWarnings
中,用來抑制編譯器的警告資訊,此注解需要加上參數之後才能正常使用,參數清單如下:
參數 | 說明 |
---|---|
deprecation | 使用了過時的類或方法的警告 |
unchecked | 執行了未檢查的轉換時的警告,如使用集合時未指定泛型 |
fallthrough | 當switch語句使用時發生case穿透 |
path | 在路徑、源檔案路徑等中有不存在路徑的警告 |
serial | 當在序列化的類上缺少serialVersionUID定義時的警告 |
finally | 任何finally子句不能完成的警告 |
all | 關于以上所有情況的警告 |
@SuppressWarnings("uncheck")
// 多個參數的時候以數組的形式傳遞
@SuppressWarnings(value = {"unchecked","deprecation"})
自定義注解
元注解
- 在自定義注解的時候,要在注解的定義上面加上幾個元注解
-
@Target
- 作用:用于描述注解的使用範圍(即:被描述的注解可以用在什麼地方)
所修飾的範圍 | 取值 |
---|---|
| |
類、接口、枚舉、 類型 | |
類型成員(方法、構造方法、成員變量、枚舉值) | :用來描述構造器 :用于描述域 :用于描述方法 |
方法參數和本地變量 | :用于描述局部變量 :用于描述參數 |
例如:
public class AnnotationTest {
@MyAnnotation
private void print(){
System.out.println("AnnotationTest.print");
}
}
@Target(ElementType.METHOD)
@interface MyAnnotation{
}
檢視
@Target
注解的源代碼
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
可以發現它的參數是一個數組,是以我們可以定義多個
ElementType
,如下
@MyAnnotation
public class AnnotationTest {
@MyAnnotation
private void print(){
System.out.println("AnnotationTest.print");
}
}
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@interface MyAnnotation{
}
-
@Retention
- 作用:表示需要在什麼級别儲存該注解資訊,用于描述注解生命周期
取值 | 作用 |
---|---|
| 在源檔案中有效(即源檔案保留) |
| 在class檔案中有效(即class保留) |
| 在運作時有效(即運作時保留)為Runtime可以被反射讀取 |
自定義注解一般用RUNTIME
-
@Document
- 表示将注解包含在Javadoc中
-
@Inherited
- 表示允許子類繼承父類中的注解
參數
- 自定義注解的參數在注解體内定義,可以設定預設值,格式如下
@MyAnnotation
public class AnnotationTest {
@MyAnnotation(name = "小李", info = {"info1", "info2"})
private void print() {
System.out.println("AnnotationTest.print");
}
}
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
int type() default 0;
String name() default "匿名使用者";
String[] info() default {};
}
注意:當注解中隻有一個參數的時候,通常将參數名定義為 value
,并且在指派的時候可以省略參數名
@MyAnnotation2("demo")
public class AnnotationTest2 {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
String value();
}
利用反射解析自定義注解
- 需求:實作與Spring Data Jpa相似的功能,将一個實體類轉化為資料庫中一張表,需要解析出實體類對應的表名、字段名,然後用JDBC建立表。這裡隻用此例子解釋解析注解的原理,不深入探究Spring Data Jpa的底層實作
- 自定義注解
Table
package com.qianyu.mianshiti.annotation;
import java.lang.annotation.*;
/**
* @author lijing
* @date 2019-09-28 11:44
* @description 表名
*/
@Target(ElementType.TYPE)
// 隻有RetentionPolicy.RUNTIME類型才能用反射解析
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
// 對應表名
String value();
}
- 自定義注解
Column
package com.qianyu.mianshiti.annotation;
import java.lang.annotation.*;
/**
* @author lijing
* @date 2019-09-28 11:48
* @description 列名
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String name();
boolean unique() default false;
boolean nullable() default true;
}
- 實體類
package com.qianyu.mianshiti.annotation;
/**
* @author lijing
* @date 2019-09-28 11:42
* @description 對應t_user表
*/
@Table("t_user")
public class User {
@Column(name = "u_id", unique = true, nullable = false)
private Integer id;
@Column(name = "u_name")
private String name;
@Column(name = "u_age")
private Integer age;
}
- 解析注解
package com.qianyu.mianshiti.annotation;
import java.lang.annotation.*;
import java.lang.reflect.*;
/**
* @author lijing
* @date 2019-09-28 11:54
* @description 解析annotation
*/
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class clazz = Class.forName("com.qianyu.mianshiti.annotation.User");
Annotation[] annotations = clazz.getAnnotations();
// 擷取類上所有注解
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
// 根據注解名擷取類注解
Table table = (Table)clazz.getAnnotation(Table.class);
System.out.println(table.value());
// 根據注解名擷取屬性的注解
Field id = clazz.getDeclaredField("id");
Column column = id.getAnnotation(Column.class);
System.out.println(column.name());
System.out.println(column.unique());
System.out.println(column.nullable());
/**
* 拼接SQL,使用JDBC操作資料庫.....
*/
}
}
- 運作結果: