Java中自定義注解介紹與使用場(chǎng)景詳解
注解的概念及分類
1.首先我們來(lái)看一下什么是注解:
注解就是某種注解類型的一個(gè)實(shí)例,我們可以用它在某個(gè)類上進(jìn)行標(biāo)注,這樣編譯器在編譯我們的文件時(shí),會(huì)根據(jù)我們自己設(shè)定的方法來(lái)編譯類。
2.注解的分類
注解大體上分為三種:標(biāo)記注解,一般注解,元注解,@Override用于標(biāo)識(shí),該方法是繼承自超類的。這樣,當(dāng)超類的方法修改后,實(shí)現(xiàn)類就可以直接看到了。而@Deprecated注解,則是標(biāo)識(shí)當(dāng)前方法或者類已經(jīng)不推薦使用,如果用戶還是要使用,會(huì)生成編譯的警告。
本文主要介紹的是關(guān)于Java自定義注解,下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧
隨著springboot的流行,以前基于XML的spring配置用的越來(lái)越少,JavaConfig形式使用的越來(lái)越多,類似于:
@Configuration public class AppConfig { @Bean(name="helloBean") public HelloWorld helloWorld() { return new HelloWorldImpl(); } }
可以看出更多的是基于注解(Annotation)實(shí)現(xiàn)的,包括springboot的入口類**Application。
@Configuration @ComponentScan("com.alibaba.trade") @EnableAutoConfiguration//(exclude = {PageHelperAutoConfiguration.class}) @ServletComponentScan @EnableTransactionManagement @EnableDiscoveryClient @EnableWebMvc @MapperScan("com.alibaba.trade.shared.mapper") public class TradeApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(TradeApplication.class, args); } }
Java注解不僅讓我們減少了項(xiàng)目中XML文件,方便了維護(hù),同時(shí)也使我們代碼更簡(jiǎn)潔。那么項(xiàng)目中我們?nèi)绾伍喿x注解以及如何創(chuàng)造自己的注解呢?
注解說(shuō)明
Java注解又稱Java標(biāo)注,是Java語(yǔ)言5.0版本開(kāi)始支持加入源代碼的特殊語(yǔ)法元數(shù)據(jù)。為我們?cè)诖a中添加信息提供了一種形式化的方法,使我們可以在稍后某個(gè)時(shí)刻非常方便的使用這些數(shù)據(jù)。
Java語(yǔ)言中的類、方法、變量、參數(shù)和包等都可以被標(biāo)注。和Javadoc不同,Java注解可以通過(guò)反射獲取注解內(nèi)容。在編譯器生成類文件時(shí),注解可以被嵌入到字節(jié)碼中。Java虛擬機(jī)可以保留注解內(nèi)容,在運(yùn)行時(shí)可以獲取到注解內(nèi)容。
注解本身沒(méi)有具體的功能,它相當(dāng)于一個(gè)標(biāo)注,而這個(gè)標(biāo)注具體的作用和意義需要我們自己實(shí)現(xiàn)。一般都是先判斷類或?qū)傩允欠癖辉撟⒔庑揎椩偻ㄟ^(guò)反射來(lái)獲取注解屬性再實(shí)現(xiàn)具體業(yè)務(wù)功能。
內(nèi)置注解
Java 定義了一套注解,共有 7 個(gè),3 個(gè)在 java.lang 中,剩下 4 個(gè)在 java.lang.annotation 中。
1、作用在代碼的注解是
- @Override - 檢查該方法是否是重載方法。如果發(fā)現(xiàn)其父類,或者是引用的接口中并沒(méi)有該方法時(shí),會(huì)報(bào)編譯錯(cuò)誤。
- @Deprecated - 標(biāo)記過(guò)時(shí)方法。如果使用該方法,會(huì)報(bào)編譯警告。
- @SuppressWarnings - 指示編譯器去忽略注解中聲明的警告。
2、作用在其他注解的注解(或者說(shuō)元注解)是:
- @Retention - 標(biāo)識(shí)這個(gè)注解怎么保存,是只在代碼中,還是編入class文件中,或者是在運(yùn)行時(shí)可以通過(guò)反射訪問(wèn)。
- @Documented - 標(biāo)記這些注解是否包含在用戶文檔中。
- @Target - 標(biāo)記這個(gè)注解應(yīng)該是哪種 Java 成員。
- @Inherited - 標(biāo)記這個(gè)注解是繼承于哪個(gè)注解類(默認(rèn)注解并沒(méi)有繼承于任何子類)
3、從 Java 7 開(kāi)始,額外添加了 3 個(gè)注解:
- @SafeVarargs - Java 7 開(kāi)始支持,忽略任何使用參數(shù)為泛型變量的方法或構(gòu)造函數(shù)調(diào)用產(chǎn)生的警告。
- @FunctionalInterface - Java 8 開(kāi)始支持,標(biāo)識(shí)一個(gè)匿名函數(shù)或函數(shù)式接口。
- @Repeatable - Java 8 開(kāi)始支持,標(biāo)識(shí)某注解可以在同一個(gè)聲明上使用多次。
元注解
1、@Retention
@Retention annotation指定標(biāo)記注釋的存儲(chǔ)方式:
- RetentionPolicy.SOURCE - 標(biāo)記的注釋僅保留在源級(jí)別中,并由編譯器忽略。
- RetentionPolicy.CLASS - 標(biāo)記的注釋在編譯時(shí)由編譯器保留,但Java虛擬機(jī)(JVM)會(huì)忽略。
- RetentionPolicy.RUNTIME - 標(biāo)記的注釋由JVM保留,因此運(yùn)行時(shí)環(huán)境可以使用它。
2、@Documented
@Documented 注釋表明,無(wú)論何時(shí)使用指定的注釋,都應(yīng)使用Javadoc工具記錄這些元素(默認(rèn)情況下,注釋不包含在Javadoc中)。有關(guān)更多信息,請(qǐng)參閱 Javadoc工具頁(yè)面。
3、@Target
@Target 注釋標(biāo)記另一個(gè)注釋,以限制可以應(yīng)用注釋的Java元素類型。目標(biāo)注釋指定以下元素類型之一作為其值。
- ElementType.TYPE 可以應(yīng)用于類的任何元素。
- ElementType.FIELD 可以應(yīng)用于字段或?qū)傩浴?/li>
- ElementType.METHOD 可以應(yīng)用于方法級(jí)注釋。
- ElementType.PARAMETER 可以應(yīng)用于方法的參數(shù)。
- ElementType.CONSTRUCTOR 可以應(yīng)用于構(gòu)造函數(shù)。
- ElementType.LOCAL_VARIABLE 可以應(yīng)用于局部變量。
- ElementType.ANNOTATION_TYPE 可以應(yīng)用于注釋類型。
- ElementType.PACKAGE 可以應(yīng)用于包聲明。
- ElementType.TYPE_PARAMETER
- ElementType.TYPE_USE
4、@Inherited
@Inherited 注釋表明注釋類型可以從超類繼承。當(dāng)用戶查詢注釋類型并且該類沒(méi)有此類型的注釋時(shí),將查詢類的超類以獲取注釋類型(默認(rèn)情況下不是這樣)。此注釋僅適用于類聲明。
5、@Repeatable
Repeatable Java SE 8中引入的,@Repeatable注釋表明標(biāo)記的注釋可以多次應(yīng)用于相同的聲明或類型使用(即可以重復(fù)在同一個(gè)類、方法、屬性等上使用)。
自定義注解
Java中自定義注解和創(chuàng)建一個(gè)接口相似,自定義注解的格式是以@interface為標(biāo)志的。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface SPI { /** * default extension name */ String value() default ""; }
我們知道java.lang.annotation包中有一個(gè)Annotation的接口,它是所有注解類型擴(kuò)展的公共接口。那我們是否可以直接通過(guò)實(shí)現(xiàn)該接口來(lái)實(shí)現(xiàn)自定義注解呢?
import java.lang.annotation.Annotation; public class MyAnnotation implements Annotation { @Override public Class<? extends Annotation> annotationType() { return null; } }
發(fā)現(xiàn)Annotation接口中只有一個(gè)annotationType的方法,而且通過(guò)Annotation源碼的注釋我們可以發(fā)現(xiàn)答案是不能。
漢譯即為:Annotaion被所有注解類型繼承,但是要注意:手動(dòng)擴(kuò)展繼承此接口的接口不會(huì)定義注解類型。另請(qǐng)注意,此接口本身不定義注解類型。
使用場(chǎng)景
自定義注解的使用場(chǎng)景很多,我們?cè)谠燧喿訉懣蚣艿倪^(guò)程經(jīng)常會(huì)使用到,例如我最近就遇到了一個(gè)業(yè)務(wù)場(chǎng)景:像一些編輯業(yè)務(wù)信息的接口,產(chǎn)品要求信息編輯后的新舊值對(duì)比,對(duì)比的業(yè)務(wù)功能,我們的實(shí)現(xiàn)方式是拿到前端填寫的Form表單(新值)和數(shù)據(jù)庫(kù)中查詢出來(lái)的Dto(舊值)通過(guò)反射技術(shù)獲取到相同屬性字段名,再比較屬性值就可以得出新舊值。得到值之后我們也知道該字段的Dto中的字段名,但是如何將比較得到的新舊值字段的中文名返回給前端呢?例如:
public class Stedent { private String name; private int age; private String sex; //省略setter,getter }
比較后我們的結(jié)果是 name : “xiaoming “-> “daming”,age : 24 -> 26。但是我們不能直接將name和age返回給前端,他們需要的格式是:姓名: “xiaoming “-> “daming”,年齡 : 24 -> 26。這時(shí)候就可以考慮自定義一個(gè)注解@FieldName,
@Deprecated @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface FieldName { String value() default ""; }
然后將該注解加在屬性字段上面
public class Student { @FieldName(value = "姓名") private String name; @FieldName(value = "年齡") private int age; @FieldName(value = "性別") private String sex; //省略setter,getter }
之后就可以通過(guò)反射獲取該字段中文名。
// 如果 oldField 屬性值與 newField 屬性值的內(nèi)容不相同 if (!isEmpty(newValue)) { Map<String, Object> map = new HashMap<>(); String newFieldName = newField.getName(); if (newField.isAnnotationPresent(ApiModelProperty.class)) { ApiModelProperty apiModelPropertyAnno = newField.getAnnotation(ApiModelProperty.class); newFieldName = apiModelPropertyAnno.value(); else if (newField.isAnnotationPresent(FieldName.class)) { FieldName fieldNameAnno = newField.getAnnotation(FieldName.class); newFieldName = fieldNameAnno.name(); } map.put(FIELD_NAME, newFieldName); map.put(OLD_VALUE, oldValue); map.put(NEW_VALUE, newValue); list.add(map); }
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Java實(shí)現(xiàn)登錄與注冊(cè)頁(yè)面
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)登錄與注冊(cè)頁(yè)面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04Java鎖升級(jí)的實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了Java鎖升級(jí)的實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05使用springboot通過(guò)spi機(jī)制加載mysql驅(qū)動(dòng)的過(guò)程
這篇文章主要介紹了使用springboot通過(guò)spi機(jī)制加載mysql驅(qū)動(dòng)的過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07

Mac使用Idea配置傳統(tǒng)SSM項(xiàng)目(非maven項(xiàng)目)

spring boot項(xiàng)目fat jar瘦身的實(shí)現(xiàn)

SpringBoot整合MOTT動(dòng)態(tài)讀取數(shù)據(jù)庫(kù)連接信息并連接MQTT服務(wù)端

idea新建maven項(xiàng)目沒(méi)有src目錄的操作方法