1. 程式人生 > >JAVA註解開發(精講)

JAVA註解開發(精講)

在這裡插入圖片描述
Java註解開發
一. 什麼是註解
Annotation(註解)就是Java提供了一種為程式元素關聯任何資訊或任何元資料(metadata)的途徑和方法。Annotion(註解)是一個介面,程式可以通過反射來獲取指定程式元素的Annotion物件,然後通過Annotion物件來獲取註解裡面的元資料。

  1. 註解出現的位置
    Annotation(註解)是JDK5.0及以後版本引入的。它可以用於建立文件,跟蹤程式碼中的依賴性,甚至執行基本編譯時檢查。從某些方面看,annotation就像修飾符一樣被使用,並應用於包、型別、構造方法、方法、成員變數、引數、本地變數的宣告中。這些資訊被儲存在Annotation的“name=value”結構對中。

  2. 註解的成員提供了程式元素的關聯資訊(成員稱為引數或註解屬性)
    Annotation的成員在Annotation型別中以無引數的方法的形式被宣告。其方法名和返回值定義了該成員的名字和型別。在此有一個特定的預設 語法:允許宣告任何Annotation成員的預設值。一個Annotation可以將name=value對作為沒有定義預設值的Annotation 成員的值,當然也可以使用name=value對來覆蓋其它成員預設值。這一點有些近似類的繼承特性,父類的建構函式可以作為子類的預設建構函式,但是也 可以被子類覆蓋。

  3. 註解不會影響程式程式碼的執行
    Annotation能被用來為某個程式元素(類、方法、成員變數等)關聯任何的資訊。需要注意的是,這裡存在著一個基本的規則:Annotation不能影響程式程式碼的執行,無論增加、刪除 Annotation,程式碼都始終如一的執行。另外,儘管一些annotation通過java的反射api方法在執行時被訪問,而java語言直譯器在工作時忽略了這些annotation。正是由於java虛擬機器忽略了Annotation,導致了annotation型別在程式碼中是“不起作用”的; 只有通過某種配套的工具才會對annotation型別中的資訊進行訪問和處理
    5、註解的作用是什麼

註解(Annotation) 為我們在程式碼中新增資訊提供了一種形式化的方法,是我們可以在稍後 某個時刻方便地使用這些資料(通過 解析註解 來使用這些資料),常見的作用有以下幾種:
(1).生成文件。這是最常見的,也是java 最早提供的註解。常用的有@see @param @return 等;
(2).在編譯時進行格式檢查。如@Override放在方法前,如果你這個方法並不是覆蓋了超類方法,則編譯時就能檢查出;
(3).跟蹤程式碼依賴性,實現替代配置檔案功能。比較常見的是spring 2.5 開始的基於註解配置。作用就是減少配置。現在的框架基本都使用了這種配置來減少配置檔案的數量;

二.JDK自帶的註解

  1. @Override 表示當前方法覆蓋了父類的方法
    此註釋只適用於修辭方法,表示一個方法宣告打算重寫超類中的另一個方法宣告。如果方法利用此註釋型別進行註解但沒有重寫超類方法,則編譯器
    會生成一條錯誤訊息
    在這裡插入圖片描述
  2. @Deprecated 表示方法已經過時,方法上有橫線,使用時會有警告。
    此註釋可用於修辭方法、屬性、類,表示不鼓勵程式設計師使用這樣的元素,通常是因為它很危險或存在更好的選擇。在使用不被贊成的程式元素或在不被贊成的程式碼中執行重寫時,編譯器會發出警告
    在這裡插入圖片描述

在這裡插入圖片描述
3. @SuppressWarings 表示關閉一些警告資訊(通知java編譯器忽略特定的編譯警告)
用來抑制編譯時的警告資訊。與前兩個註釋有所不同,你需要新增一個引數才能正確使用,這些引數值都是已經定義好了的,我們選擇性的使用就好了,
引數如下:
在這裡插入圖片描述
在這裡插入圖片描述

例項程式碼:
在這裡插入圖片描述

我們在方法上面加上 @SuppressWarnings(“rawtypes”) .這是泛型的警告就會消失.但是還有一個變數未使用的警告
我們可以新增多種型別,多種型別用{}擴起來

在這裡插入圖片描述
另外,由於@SuppressWarnings註釋只有一個引數,並且引數名為value,所以我們可以將上面一句註釋簡寫為
@SuppressWarnings(“unchecked”);
同時引數value可以取多個值如:
@SuppressWarnings(value={“unchecked”, “deprecation”})
或@SuppressWarnings({“unchecked”, “deprecation”})。

三.開發自定義註解

  1. 自定義註解的語法規則
    (1).使用@interface關鍵字定義註解,注意關鍵字的位置
    使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation介面,由編譯程式自動完成其他細節。在定義註解時,不能繼承其他的註解或介面。
    (2).成員以無引數無異常的方式宣告,注意區別一般類成員變數的宣告
    其中的每一個方法實際上是聲明瞭一個配置引數。方法的名稱就是引數的名稱
    (3).可以使用default為成員指定一個預設值,如上所示
    (4).成員型別是受限的,合法的型別包括原始型別以及String、Class、Annotation、Enumeration (JAVA的基本資料型別有8種:
    byte(位元組)、short(短整型)、int(整數型)、long(長整型)、float(單精度浮點數型別)、double(雙精度浮點數型別)、char(字元型別)、boolean(布林型別)
    (5).註解類可以沒有成員,沒有成員的註解稱為標識註解,例如JDK註解中的@Override、@Deprecation
    (6).如果註解只有一個成員,並且把成員取名為value(),則在使用時可以忽略成員名和賦值號“=” ,例如JDK註解的@SuppviseWarnings ;如果成員名 不為value,則使用時需指明成員名和賦值號"=",

在這裡插入圖片描述在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

  1. 元註解:
    何為元註解?就是註解的註解,就是給你自己定義的註解添加註解,你自己定義了一個註解,但你想要你的註解有什麼樣的功能,此時就需要用元註解對你的註解進行說明了。Java5.0定義了4個標準的meta-annotation型別,它們被用來提供對其它 annotation型別作說明。
    在這裡插入圖片描述

2.1、@Target
@Target說明了Annotation所修飾的物件範圍:即註解的作用域,用於說明註解的使用範圍(即註解可以用在什麼地方,比如類的註解,方法註解,成員變數註解等等)
注意:如果Target元註解沒有出現,那麼定義的註解可以應用於程式的任何元素。
取值是在java.lang.annotation.ElementType這個列舉中規定的:
1.CONSTRUCTOR:用於描述構造器
2.FIELD:用於描述域
3.LOCAL_VARIABLE:用於描述區域性變數
4.METHOD:用於描述方法
5.PACKAGE:用於描述包
6.PARAMETER:用於描述引數
7.TYPE:用於描述類、介面(包括註解型別) 或enum宣告
例項程式碼
在這裡插入圖片描述

2.2 @Retention
@Retention定義了該Annotation被保留的時間長短:
(1)某些Annotation僅出現在原始碼中,而被編譯器丟棄;
(2)而另一些卻被編譯在class檔案中;編譯在class檔案中的Annotation可能會被虛擬機器忽略,
(3)而另一些在class被裝載時將被讀取(請注意並不影響class的執行,因為Annotation與class在使用上是被分離的)。
使用這個meta-Annotation可以對 Annotation的“生命週期”限制。
@Retention的取值是在RetentionPoicy這個列舉中規定的
1.SOURCE:在原始檔中有效(即原始檔保留)
2.CLASS:在class檔案中有效(即class保留)
3.RUNTIME:在執行時有效(即執行時保留)

例項程式碼如下:

在這裡插入圖片描述
注意:註解的的RetentionPolicy的屬性值是RUTIME,這樣註解處理器可以通過反射,獲取到該註解的屬性值,從而去做一些執行時的邏輯處理

2.3、@Documented
@Documented用於描述其它型別的annotation應該被作為被標註的程式成員的公共API,因此可以被例如javadoc此類的工具文件化。Documented是一個標記註解,沒有成員。

2.4、@Inherited
@Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的型別是被繼承的。如果一個使用了@Inherited修飾的annotation型別被用於一個class,則這個annotation將被用於該class的子類。
注意:@Inherited annotation型別是被標註過的class的子類所繼承。類並不從它所實現的介面繼承annotation,方法並不從它所過載的方法繼承annotation。
當@Inherited annotation型別標註的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這種繼 承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation型別的annotation時,反射程式碼檢查將展開工作:檢查class和其父類,直到發現指定的annotation型別被發現, 或者到達類繼承結構的頂層。
(1) 定義註解1
在這裡插入圖片描述
(2) 定義註解2
在這裡插入圖片描述

(3) 定義一個基類
在這裡插入圖片描述
(4) 定義一個子類
在這裡插入圖片描述
(5) 通過反射獲取子類中使用的所有的註解
在這裡插入圖片描述

四.註解開發例項:通過註解建立資料庫表

  1. 建立Column註解,表示資料庫中的欄位資訊
    在這裡插入圖片描述

  2. 建立Table註解,表示資料庫中的表
    在這裡插入圖片描述

  3. 建立JavaBen類,使用定義的註解

在這裡插入圖片描述

  1. 建立Main方法,讀取JavaBen類中的註解資訊,根據註解資訊自動生成DDL語句

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述*****************************


1.Java中的註釋型別Annotation是一種引用資料型別,也稱為註解。*

自定義註釋的開發過程。
no.1.宣告一個類My Annotation
no.2.把class 關鍵字改成 @interface,實質上聲明瞭一個介面,這個介面自動的繼承了Java.lang.annotation.Annotation介面。

2.常用內建註解: @Override @Deprecated @SuppressWarnings,以及它們各自的作用。*

   @Deprecated,表示這個方法過時了,最好別用了  @Override表示方法重寫,或者覆蓋。
   @SuppressWarnings讓編譯器忽略警告資訊。 (@suppressWarnings({rawtypes}))
   @suppressWarnings(value = {rawtypes})//泛型

3.自定義註解的時候,這幾個註解你知道分別是幹什麼的嗎? @Retention @Target @Inherited @Documented*

no1. //@Target元註解是用來限定自定義註解的使用範圍的。
@Target說明了Annotation所修飾的物件範圍:即註解的作用域,
用於說明註解的使用範圍(即註解可以用在什麼地方,比如類的註解,方法註解,成員變數註解等等)
注意:如果Target元註解沒有出現,那麼定義的註解可以應用於程式的任何元素。
@Target取值是在java.lang.annotation.ElementType這個列舉中規定的:
//@Target({ ElementType.TYPE }) // 規定了自定義註解的使用範圍是:只能在型別上面使用
@Target({ ElementType.TYPE, ElementType.METHOD }) // 規定了自定義註解的使用範圍是:可以在型別上面使用,也可以在方法上面使用
@Retention(RetentionPolicy.RUNTIME) // 註解資訊在執行時保留

public @interface MyAnnotation {
int age();

String name();

String schoolName() default "動力節點";

}
[email protected]定義了該Annotation被保留的時間長短:
// (1)某些Annotation僅出現在原始碼中,而被編譯器丟棄;
// (2)而另一些卻被編譯在class檔案中;編譯在class檔案中的Annotation可能會被虛擬機器忽略,執行時被忽略
// (3)而另一些在class被裝載時將被讀取(請注意並不影響class的執行,因為Annotation與class在使用上是被分離的)。
// 使用這個meta-Annotation可以對 Annotation的“生命週期”限制。
// @Retention的取值是在RetentionPoicy這個列舉中規定的
// 1.SOURCE:在原始檔中有效(即原始檔保留)
// 2.CLASS:在class檔案中有效(即class保留)
// 3.RUNTIME:在執行時有效(即執行時保留,注意:只有註解資訊在執行時保留,我們才能在執行時通過反射讀取到註解資訊)
// 註解的保留範圍,只能三選一

[email protected]儲存檔案的

[email protected]父類中使用的註解可以被子類繼承.

自定義註解實際上就是一種型別而已,也就是引用型別(Java中除了8種基本型別之外,我們見到的任何型別都是引用型別)
型別的作用:(1)宣告變數;(2)宣告方法的引數;(3)宣告方法的返回型別;(4)強制型別轉換
因為我們在註解中聲明瞭屬性,所以在使用註解的時候必須要指明 屬性值 ,多個屬性之間沒有順序,多個屬性之間通過逗號分隔
4.能夠通過反射機制讀取註解嗎?*

package com.bjpowernode.annotationtest10;

import java.lang.reflect.Field;

public class ReflectTest {

/**
 * 通過反射操作,獲取類中攜帶的註解資訊.根據讀取到的資訊生成資料庫的建表語句
 * 
 * @return
 */
public static String buildSql() {

	// 準備資料庫的建表語句
	StringBuilder str = new StringBuilder("CREATE TABLE ");

	// 獲取Emp類對應的Class物件
	Class claz = Emp.class;

	// =============================================================
	// 一.獲取Emp類中攜帶的@Table註解,以此來獲取表名資訊

	// (1)獲取Emp類中攜帶的Table註解
	Table table = (Table) claz.getAnnotation(Table.class);
      System.out.println(table);
	// (2)獲取Table註解中的的屬性資訊
	String tableName = table.tableName();// 獲取表名資訊
        System.out.println(tableName);
	// (3)把表名資訊拼接到SQL語句中
	str.append(tableName + " (");

	// =============================================================
	// 二:獲取Emp類中攜帶的Column註解,來獲取欄位的相關資訊

	// (1)獲取類中宣告的所有的屬性
	Field[] fields = claz.getDeclaredFields();

	// (2)遍歷儲存所有屬性的Field的陣列,取出每個屬性
	for (Field field : fields) {

		// (3)判斷屬性中是否使用了Column註解
		if (field.isAnnotationPresent(Column.class)) {
			// (4)獲取屬性中使用的Column註解
			Column column = field.getAnnotation(Column.class);

			// (5)獲取註解中攜帶的欄位資訊
			String columnName = column.columnName(); // 獲取欄位名資訊
			String columnType = column.columnType(); // 獲取欄位型別資訊
			int columnLength = column.columnLength(); // 獲取欄位長度資訊
			String columnConstraint = column.columnConstraint(); // 獲取欄位約束資訊

			// (6)把欄位的相關資訊拼接到SQL語句中
			if (columnName.equalsIgnoreCase("hiredate")) {
				str.append(columnName + " " + columnType + " " + columnConstraint + ",");
		  System.out.println(str);
				 System.out.println();
			}    else {
				
				str.append(columnName + " " + columnType + " (" + columnLength + ") " + columnConstraint + ",");
				System.out.println(str);
			}
		}
	}

	// 去除SQL中最末尾的逗號,並且關閉SQL語句中的()
	String sql = str.substring(0, str.length() -1) + ")";//擷取字串語句。
	return sql;
}

public static void main(String[] args) {
	String sql = buildSql();
 	System.out.println(sql);
}

}

5.java中的Annotation/註釋型別,它有什麼用?*

是為了在其他類中使用這個註釋(使用註解來攜帶資訊),這些攜帶資訊可以在其他類的任何位置使用
從某些方面來看,annotatiom就像是一個修飾符一樣來使用 ,並用於包,型別,方法,構造方法,成員變數,引數,本地變數宣告中。
必須要和反射一起操作。【通過class 獲取類的相關資訊,通過class建立物件,通過class呼叫物件的方法和屬性,這種操作稱為反射操作。】

要想執行反射操作,必須先獲取指定類名的class。
eg.String.class
class.forname("字串")
String obj="Hello",Class claz = obj.getClass()



6. 註解中宣告屬性的語法比較怪異,即像在Java類中宣告屬性,又像在Java類中宣告方法(實際上:即是聲明瞭屬性,又是聲明瞭方法)
  註解中宣告屬性的規範: 屬性型別 屬性名稱 ();
  屬性名稱的規範:名詞或名詞性短語,第一個單詞首字元小寫,其餘單詞首字元大寫



  在使用註解的時候,通過註解中的屬性來攜帶資訊

因為我們在註解中聲明瞭屬性,所以在使用註解的時候必須要指明屬性值,多個屬性之間沒有順序,多個屬性之間通過逗號分隔

7.可以給註解中的屬性提供預設值
// 我們可以在註解中宣告屬性.(在註解中通過屬性來攜帶資訊)

    public @interface MyAnnotation {
// 註解中宣告屬性的語法比較怪異,即像在Java類中宣告屬性,又像在Java類中宣告方法(實際上:即是聲明瞭屬性,又是聲明瞭方法)
// 註解中宣告屬性的規範: 屬性型別 屬性名稱 ();
// 屬性名稱的規範:名詞或名詞性短語,第一個單詞首字元小寫,其餘單詞首字元大寫
int age();

String name();

// 可以給註解中的屬性提供預設值
String schoolName() default "動力節點";

int  [] arr() ;

8.如果註解中只有一個屬性,並且屬性名稱是value,這樣的話我們使用註解的時候,可以指明屬性名稱,也可以忽略屬性名稱
    
 
 @MyAnnotation(value = { "Hello", "World" })
       public class Main {

@MyAnnotation({ "Hello", "World" })
public static void main(String[] args) {

}

	package com.bjpowernode.annotation8;

         public @interface MyAnnotation {
       String[] value();
      }  

9.方法重寫要求訪問許可權不能降低,
priority : private 私有的,訪問許可權最低
default預設的
protected 受保護的 父子關係中常用
public 訪問許可權最高。

也不能丟擲比父類更多的異常。 exceotion
IO exception
file not found

10.現實中的一個實體對應著一個數據庫表;一個數據庫表會對應著一個Java類;
實體中的屬性成為表中的欄位;表中的欄位對應著類中的屬性

和資料庫表對應著的類稱為JavaBean類,JavaBean的規範
1.類中的屬性私有化,並且提供公開的getter/settter()方法
2.類中覆蓋toString()方法 (為了輸出物件做好了準備)
3.類中覆蓋hashCode()/equals()方法(覆蓋hashCode()/equals()的目的是為了把JavaBean類的物件放到HashMap/HashSet中做好準備)
4.類中提供公開的無引數的構造方法
5.該類要實現Serialiazble介面,並且宣告serialVersionUID(使用Eclipse工具生成的) 為序列化做好了準備

我們要執行的功能,根據一個寫好的JavaBean類,自動的生成資料庫的建表語句(DDL)
建立資料庫表所需要的資訊:
(1)表名資訊
(2)欄位的資訊,包括 欄位名稱,欄位型別,欄位長度,欄位約束

我們如何來攜帶上面的建表所需要的資訊呢?使用註解!
1.為了在JavaBean類中攜帶表名資訊,我們建立一個@Table的註解,這個註解在型別上面使用,因為一個JavaBean類對應一個表
2.為了在JavaBean類中攜帶欄位資訊,我們建立一個@Column的註解,這個註解在類的屬性中使用;因為類的屬性對應著表中的欄位

註解在實際開發中的作用
使用註解在類中攜帶資訊,程式執行的時候通過反射操作獲取到註解資訊,然後根據獲取到的資訊生成資料庫的建表語句

程式中攜帶資訊的方式
1.通過註解來攜帶資訊,然後通過反射來讀取資訊
2.通過檔案來攜帶資訊,然後通過IO來讀取資訊