什么是注解?
Java 注解(Annotation)又稱 Java 標(biāo)注,是 JDK5.0 引入的一種注釋機(jī)制。 比如我們常見的@Override和@Deprecated都是注解,注解可以加在類、方法、成員變量等上面,類似于給他們“打標(biāo)簽"。
注解怎么定義?
public @interface 注解名{} 看起來和定義接口很相似只是多了一個(gè)@符號(hào) 接口: public interface 接口名 注解: public @interface 注解名
public @interface lkx {
}
注解怎么使用?
現(xiàn)在我們注解已經(jīng)定義好了,使用的時(shí)候直接“@注解名”就可以使用了 比如下面我們可以定義在“類、成員變量、成員方法”上:
@lkx
public class Test {
@lkx
private int num;
@lkx
public static void main(String[] args) {
System.out.println("hello");
}
}
-
思考一下
現(xiàn)在注解定義好也已經(jīng)使用了,但是我不想定義到類上和成員方法上,只想定義在成員方法上,如何才能讓注解只能定義到方法上,定義到別的地方報(bào)錯(cuò)呢? 想要的效果:
這個(gè)時(shí)候就要使用元注解來限定范圍了。
元注解
元注解通俗的來說就是定義在注解上的注解,在Java中有四個(gè)元注解 @Target @Retention @Documented @Inherited
@Target
@Target就是用于描述注解的定義范圍,可以限制這個(gè)注解定義的元素類型。
參數(shù) | 作用 |
---|---|
ElementType.ANNOTATION_TYPE | 可以應(yīng)用于注解類型 |
ElementType.CONSTRUCTOR | 可以應(yīng)用于構(gòu)造函數(shù) |
ElementType.FIELD | 可以應(yīng)用于字段或?qū)傩?/td> |
ElementType.LOCAL_VARIABLE | 可以應(yīng)用于局部變量 |
ElementType.METHOD | 可以應(yīng)用于方法級(jí)注解 |
ElementType.PACKAGE | 可以應(yīng)用于包聲明 |
ElementType.PARAMETER | 可以應(yīng)用于方法的參數(shù) |
ElementType.TYPE | 可以應(yīng)用于類的任何元素 |
因?yàn)槲覀円拗浦幌攵x在成員變量上,所以我們應(yīng)該使用ElementType.FIELD
@Target(ElementType.FIELD)
public @interface lkx {
}
但是如果我們想同時(shí)定義在成員變量和成員方法上應(yīng)該怎么辦呢? 多個(gè)參數(shù)只需要用大括號(hào)包起來,逗號(hào)隔開就可以了
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface lkx {
}
現(xiàn)在就只有定義在類上的注解報(bào)錯(cuò)了
@Retention
@Retention是用于定義注解的生命周期,也可以理解為存儲(chǔ)方式。
參數(shù) | 作用 |
---|---|
RetentionPolicy.SOURCE | 標(biāo)記的注解僅保留在源級(jí)別中,并被編譯器忽略 |
RetentionPolicy.CLASS | 標(biāo)記的注解在編譯時(shí)由編譯器保留,但 Java 虛擬機(jī)(JVM)會(huì)忽略 |
RetentionPolicy.RUNTIME | 標(biāo)記的注解由 JVM 保留,因此運(yùn)行時(shí)環(huán)境可以使用它 |
下面兩個(gè)元注解使用不多,暫時(shí)不做詳解
@Documented
@Documented是用于描述生成幫助文檔時(shí)是否要保留其注解信息。
@Inherited
@Inherited是用于描述使被它修飾的注解是否具有繼承性。
注解元素
上面我們只是定義了一個(gè)注解,但是不能傳任何信息,只是相當(dāng)于一個(gè)標(biāo)簽,現(xiàn)在我們看看要怎么給注解定義參數(shù):
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface lkx {
String name() default "張三"; //可以使用default定義默認(rèn)的值
int age();
}
現(xiàn)在我們看一下如何傳參:
public class Test {
//name有默認(rèn)值,也可以不寫
@lkx(name = "李四",age = 18)
private int num;
public static void main(String[] args) {
System.out.println("hello");
}
}
實(shí)戰(zhàn)
現(xiàn)在注解也定義好了,參數(shù)也傳入了,你是否還在想注解有什么卵用。?!,F(xiàn)在我們有個(gè)小需求,把注解傳入的參數(shù)賦值到成員變量上。 例如:
@lkx(name = "李四",age = 18)
private int num; //num沒有被賦值,等于0
賦值完成后
num = 18
注意事項(xiàng):
- 下面代碼需要用到反射,如果還不會(huì)的小伙伴可以看我前面幾篇文章。
- 因?yàn)橐梅瓷淠玫阶⒔鈪?shù),所以@Retention需要定義為RetentionPolicy.RUNTIME
實(shí)現(xiàn)代碼:文章來源:http://www.zghlxwxcb.cn/news/detail-770837.html
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface lkx {
String name() default "張三";
int age();
}
java復(fù)制代碼public class Test {
//name有默認(rèn)值,也可以不寫
@lkx(name = "李四",age = 18)
private static int num;
@lkx(name = "王五",age = 38)
private static int age;
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
System.out.println("賦值前: num: " + num+" age: "+age);
//拿到類的字節(jié)碼
Class<Test> testClass = Test.class;
//拿到所有成員變量
for (Field declaredField : testClass.getDeclaredFields()) {
//檢測(cè)成員變量上是否有@lkx注解
if (declaredField.isAnnotationPresent(lkx.class)) {
lkx annotation = declaredField.getAnnotation(lkx.class);
//獲取到注解中的age的值
int age = annotation.age();
declaredField.set(testClass.newInstance(),age);
}
}
System.out.println("賦值后: num: " + num+" age: "+age);
}
}
運(yùn)行結(jié)果:文章來源地址http://www.zghlxwxcb.cn/news/detail-770837.html
java復(fù)制代碼賦值前: num: 0 age: 0
賦值后: num: 18 age: 38
到了這里,關(guān)于【Java基礎(chǔ)】注解——自定義注解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!