1 注解的概述
1.1 注解的概念
-
注解是JDK1.5的新特性。
-
注解相當一種標記,是類的組成部分,可以給類攜帶一些額外的信息。
-
標記(注解)可以加在包,類,字段,方法,方法參數以及局部變量上。
-
注解是給編譯器或JVM看的,編譯器或JVM可以根據注解來完成對應的功能。
注解(Annotation)相當於一種標記,在程序中加入注解就等於為程序打上某種標記,以后,javac編譯器、開發工具和其他程序可以通過反射來了解你的類及各種元素上有無何種 標記,看你的程序有什么標記,就去干相應的事,標記可以加在包、類,屬性、方法,方法的參數以及局部變量上。
引用數據類型:類,接口,數組,枚舉,注解
1.2 注解的作用
注解的作用就是給程序帶入參數。
以下幾個常用操作中都使用到了注解:
-
生成幫助文檔:@author和@version
-
@author:用來標識作者姓名。
-
@version:用於標識對象的版本號,適用范圍:文件、類、方法。
-
使用@author和@version注解就是告訴Javadoc工具在生成幫助文檔時把作者姓名和版本號也標記在文檔中。如下圖:
IDEA中生成文檔的方式:
-
-
-
編譯檢查:@Override
-
@Override:用來修飾方法聲明。
- 用來告訴編譯器該方法是重寫父類中的方法,如果父類不存在該方法,則編譯失敗。如下圖
-
-
**框架的配置( 框架 = 代碼 + 配置 ) **
- 具體使用請關注框架課程的內容的學習。
1.3 常見注解
- @author:用來標識作者名,eclipse開發工具默認的是系統用戶名。
- @version:用於標識對象的版本號,適用范圍:文件、類、方法。
- @Override :用來修飾方法聲明,告訴編譯器該方法是重寫父類中的方法,如果父類不存在該方法,則編譯失敗。
- @Override
- @FunctionnalInterface
- @Test
- @After
- @Before
2 自定義注解
2.2.1 定義格式
public @interface 注解名{
}
如:定義一個名為Student的注解
public @interface Student {
}
注解本質上就是一個接口。所有注解都會繼承一個接口:Annotation
2.2 注解的屬性
-
屬性的格式
- 格式1:數據類型 屬性名();
- 格式2:數據類型 屬性名() default 默認值;
-
屬性定義示例
// 姓名 String name(); // 年齡 int age() default 18; // 愛好 String[] hobby();
-
屬性適用的數據類型
* 八種數據數據類型(int,short,long,double,byte,char,boolean,float) * String,Class,注解類型,枚舉類 * 以上類型的數組形式
3 使用自定義注解
3.1 定義和注解
- 定義一個注解:Book
- 包含屬性:String value() 書名
- 包含屬性:double price() 價格,默認值為 100
- 包含屬性:String[] authors() 多位作者
- 代碼實現
public @interface Book {
String value();
double price() default 100;
String[] authros();
}
3.2 使用注解
- 定義類在成員方法上使用Book注解
public class AnnotationDemo01 {
@Book(value = "JavaEE開發詳解",authros = {"黑馬程序員","傳智學院"})
public void show(){
}
}
- 使用注意事項
- 如果屬性有默認值,則使用注解的時候,這個屬性可以不用賦值。
- 如果屬性沒有默認值,那么在使用注解時一定要給屬性賦值。
3.3 特殊屬性value
如果注解中只有一個屬性且名字叫value,則在使用該注解時可以直接給該屬性賦值,而不需要給出屬性名。
如果注解中除了value屬性之外還有其他屬性且只要有一個屬性沒有默認值,則在給屬性賦值時value屬性名也不能省略了。
因此,如果注解中只有一個屬性時,一般都會將該屬性名命名為value
public class Demo01 {
@C("ccc")//如果有其他的屬性,並且都含有default,都使用默認值的情況下,只給value賦值的情況下也可以省略value=
@B(value = "bb", age = 18)//如果出了value還有其他的屬性而且沒有default數據,不能省略value=
@A("aa") //如果只有value屬性,賦值時,可以省略 value=
public void test1() {
}
}
@interface A {
String value();
}
@interface B {
String value();
int age();
}
@interface C {
String value();
int age() default 18;
}
4 注解之元注解
4.1元注解概述
Java官方提供的注解 用來定義注解的注解 任何官方提供的非元注解的定義都使用到了元注解。
元注解的作用:用來限定其他注解的生命周期,限定可以使用的地方。
4.2 常用的元注解
@Target
作用:用來標識注解使用的位置,如果沒有使用該注解標識,則自定義的注解可以使用在任意位置。
可使用的值定義在ElementType枚舉類中,常用值如下
TYPE,類,接口
FIELD, 成員變量
METHOD, 成員方法
PARAMETER, 方法參數
CONSTRUCTOR, 構造方法
LOCAL_VARIABLE, 局部變量
@Retention
作用:用來標識注解的生命周期(有效范圍)
可使用的值定義在RetentionPolicy枚舉類中,常用值如下
SOURCE:注解只作用在源碼階段,生成的字節碼文件中不存在
CLASS:注解作用在源碼階段,字節碼文件階段,運行階段不存在,【默認值】
RUNTIME:注解作用在源碼階段,字節碼文件階段,運行階段
【代碼示例】
示例中為JDK定義的@override注解
5 注解解析
什么是注解解析? 使用Java技術獲得注解上數據的過程則稱為注解解析。
與注解解析相關的接口
Annotation: 注解類的父類型,該類是所有注解的父接口。
AnnotatedElement:該接口定義了與注解解析相關的方法
1. T getAnnotation(Class<T> annotationClass)
根據注解類型獲得對應注解對象
2. Annotation[] getAnnotations()
獲得當前對象上使用的所有注解,返回注解數組,包含父類繼承的
3. Annotation[] getDeclaredAnnotations()
得當前對象上使用的所有注解,返回注解數組,只包含本類的
4. boolean isAnnotationPresent(Class<Annotation> annotationClass)
判斷當前對象是否使用了指定的注解,如果使用了則返回true,否則false
獲取注解數據的原理
Field,Method,Constructor,Class等類都是實現了AnnotatedElement接口
注解作用在哪個成員上就會得該成員對應的對象來獲得注解
比如注解作用成員方法,則要獲得該成員方法對應的Method對象
比如注解作用在類上,則要該類的Class對象
比如注解作用在成員變量上,則要獲得該成員變量對應的Field對象。
5.1 需求說明
- 定義注解Book,要求如下:
- 包含屬性:String value() 書名
- 包含屬性:double price() 價格,默認值為 100
- 包含屬性:String[] authors() 多位作者
- 限制注解使用的位置:類和成員方法上
- 指定注解的有效范圍:RUNTIME
- 定義BookStore類,在類和成員方法上使用Book注解
- 定義TestAnnotation測試類獲取Book注解上的數據
5.2 代碼實現
自定義注解
//自定義注解
@Target({ElementType.METHOD,ElementType.TYPE}) //作用在方法和類上
@Retention(RetentionPolicy.RUNTIME) //在運行時候有效
@interface Bookshelf{
//屬性
String name();
double price() default 9.9;
String[] authors();
}
注冊到Book實體類
@Bookshelf(name = "紅樓夢",price = 99.9,authors = {"曹雪芹","AAA"})
public class Book {
@Bookshelf(name = "西游記",authors = {"吳承恩","BBB"})
public void show(){}
}
測試類解析
package com.homework_test.test02;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Test {
public static void main(String[] args)throws Exception {
//創建Book類的字節碼對象(獲取類上的注解)
Class<Book> bookClass = Book.class;
//判斷該class對象是否使用了該 注解
if(bookClass.isAnnotationPresent(Bookshelf.class)){
//獲得該注解類型的對象
Bookshelf bookshelf = bookClass.getAnnotation(Bookshelf.class);
String name = bookshelf.name();
System.out.println("name = " + name);//name = 紅樓夢
String[] authors = bookshelf.authors();
System.out.println("authors = " + Arrays.toString(authors));//authors = [曹雪芹, AAA]
double price = bookshelf.price();
System.out.println("price = " + price);//price = 9.9
}
System.out.println("************************************");
//解析方法上的注解
//1.通過class對象獲取指定方法對象
Method showMethod = bookClass.getMethod("show");
//2.開始解析注解
if(showMethod.isAnnotationPresent(Bookshelf.class)){
//獲取注解對象
Bookshelf bookshelf = showMethod.getAnnotation(Bookshelf.class);
String name = bookshelf.name();
System.out.println("name = " + name);//name = 西游記
double price = bookshelf.price();
System.out.println("price = " + price);//price = 99.9
String[] authors = bookshelf.authors();
System.out.println("authors = " + Arrays.toString(authors));//authors = [吳承恩, BBB]
}
}
}