摘要:上面在將注解信息注入到方法中的時候,我們最后加上了的注解不然就會報錯了那它是干什么用的呢只能用于修飾其他的,用于指定被修飾的被保留多長時間。
前言
今天要講的是注解,對于本章節(jié),最好是有Servlet基礎(chǔ)的人查閱~因為單純是Java基礎(chǔ)的話,可能用不上注解這個東西。但如果開發(fā)過Servlet,就對@WebServlet不會陌生。
現(xiàn)在的開發(fā)都推崇使用注解來進行開發(fā),這樣就可以免去寫XML配置了,十分方便的一項技術(shù)~
學(xué)習(xí)注解可以更好地理解注解是怎么工作的,看見注解了就可以想到它的運行原理了~。
如果有錯的地方請大家多多包涵并歡迎在評論區(qū)指正~
一、什么是注解?注解:Annotation....
注解其實就是代碼中的特殊標(biāo)記,這些標(biāo)記可以在編譯、類加載、運行時被讀取,并執(zhí)行相對應(yīng)的處理。
二、為什么我們需要用到注解?傳統(tǒng)的方式,我們是通過配置文件(xml文件)來告訴類是如何運行的。
有了注解技術(shù)以后,我們就可以通過注解告訴類如何運行
例如:我們以前編寫Servlet的時候,需要在web.xml文件配置具體的信息
我們使用了注解以后,可以直接在Servlet源代碼上,增加注解...Servlet就被配置到Tomcat上了。也就是說,注解可以給類、方法上注入信息。
明顯地可以看出,這樣是非常直觀的,并且Servlet規(guī)范是推崇這種配置方式的。
三、基本Annotation在java.lang包下存在著5個基本的Annotation,其中有3個Annotation我們是非常常見的了。
3.1@Overried重寫注解
如果我們使用IDE重寫父類的方法,我們就可以看見它了。那它有什么用呢??
@Overried是告訴編譯器要檢查該方法是實現(xiàn)父類的...可以幫我們避免一些低級的錯誤...
比如,我們在實現(xiàn)equals()方法的時候,把euqals()打錯了,那么編譯器就會發(fā)現(xiàn)該方法并不是實現(xiàn)父類的,與注解@Overried沖突,于是就會給予錯誤。
3.2@Deprecated過時注解
該注解也非常常見,Java在設(shè)計的時候,可能覺得某些方法設(shè)計得不好,為了兼容以前的程序,是不能直接把它拋棄的,于是就設(shè)置它為過時。
Date對象中的toLocalString()就被設(shè)置成過時了
@Deprecated public String toLocaleString() { DateFormat formatter = DateFormat.getDateTimeInstance(); return formatter.format(this); }
當(dāng)我們在程序中調(diào)用它的時候,在IDE上會出現(xiàn)一條橫杠,說明該方法是過時的。
3.3@SuppressWarnings抑制編譯器警告注解
該注解在我們寫程序的時候并不是很常見,我們可以用它來讓編譯器不給予我們警告
當(dāng)我們在使用集合的時候,如果沒有指定泛型,那么會提示安全檢查的警告
如果我們在類上添加了@SuppressWarnings這個注解,那么編譯器就不會給予我們警告了
3.4@SafeVarargsJava 7“堆污染”警告
什么是堆污染呢??當(dāng)把一個不是泛型的集合賦值給一個帶泛型的集合的時候,這種情況就很容易發(fā)生堆污染....
這個注解也是用來抑制編譯器警告的注解...用的地方并不多,我也不詳細說明了......有用到的時候再回來填坑吧。
3.5@FunctionalInterface@FunctionalInterface用來指定該接口是函數(shù)式接口
用該注解顯示指定該接口是一個函數(shù)式接口。
四、自定義注解基礎(chǔ)上面講解的是java.lang包下的5個注解,我們是可以自己來寫注解,給方法或類注入信息。
4.1標(biāo)記Annotation沒有任何成員變量的注解稱作為標(biāo)記注解,@Overried就是一個標(biāo)記注解
//有點像定義一個接口一樣,只不過它多了一個@ public @interface MyAnnotation { }4.2元數(shù)據(jù)Annotation
我們自定義的注解是可以帶成員變量的,定義帶成員變量的注解叫做元數(shù)據(jù)Annotation
在注解中定義成員變量,語法類似于聲明方法一樣....
public @interface MyAnnotation { //定義了兩個成員變量 String username(); int age(); }
注意:在注解上定義的成員變量只能是String、數(shù)組、Class、枚舉類、注解
有的人可能會奇怪,為什么注解上還要定義注解成員變量??聽起來就很復(fù)雜了....
上邊已經(jīng)說了,注解的作用就是給類、方法注入信息。那么我們經(jīng)常使用XML文件,告訴程序怎么運行。XML經(jīng)常會有嵌套的情況
<書> <作者>zhongfucheng作者> <價錢>22222價錢> 書>
那么,當(dāng)我們在使用注解的時候,也可能需要有嵌套的時候,所以就允許了注解上可以定義成員變量為注解。
4.3使用自定義注解上面我們已經(jīng)定義了一個注解了,下面我們來使用它吧
4.3.1常規(guī)使用下面我有一個add的方法,需要username和age參數(shù),我們通過注解來讓該方法擁有這兩個變量!
//注解擁有什么屬性,在修飾的時候就要給出相對應(yīng)的值 @MyAnnotation(username = "zhongfucheng", age = 20) public void add(String username, int age) { }4.3.2默認值
當(dāng)然啦,我們可以在注解聲明屬性的時候,給出默認值。那么在修飾的時候,就可以不用具體指定了。
public @interface MyAnnotation { //定義了兩個成員變量 String username() default "zicheng"; int age() default 23; }
在修飾的時候就不需要給出具體的值了
@MyAnnotation() public void add(String username, int age) { }4.3.3注解屬性為value
還有一種特殊的情況,如果注解上只有一個屬性,并且屬性的名稱為value,那么在使用的時候,我們可以不寫value,直接賦值給它就行
public @interface MyAnnotation2 { String value(); }
使用注解,可以不指定value,直接賦值
@MyAnnotation2("zhongfucheng") public void find(String id) { }4.4把自定義注解的基本信息注入到方法上
上面我們已經(jīng)使用到了注解,但是目前為止注解上的信息和方法上的信息是沒有任何關(guān)聯(lián)的。
我們使用Servlet注解的時候,僅僅調(diào)用注解,那么注解的就生效了。這是Web容器把內(nèi)部實現(xiàn)了。我們自己寫的自定義注解是需要我們自己來處理的。
那現(xiàn)在問題來了,我們怎么把注解上的信息注入到方法上呢???我們利用的是反射技術(shù)
步驟可分為三部:
反射出該類的方法
通過方法得到注解上具體的信息
將注解上的信息注入到方法上
//反射出該類的方法 Class aClass = Demo2.class; Method method = aClass.getMethod("add", String.class, int.class); //通過該方法得到注解上的具體信息 MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); String username = annotation.username(); int age = annotation.age(); //將注解上的信息注入到方法上 Object o = aClass.newInstance(); method.invoke(o, username, age);
當(dāng)我們執(zhí)行的時候,我們發(fā)現(xiàn)會出現(xiàn)異常...
此時,我們需要在自定義注解上加入這樣一句代碼(下面就會講到,為什么要加入這句代碼)
@Retention(RetentionPolicy.RUNTIME)
再次執(zhí)行的時候,我們就會發(fā)現(xiàn),可以通過注解來把信息注入到方法中了。
五、JDK的元Annotation前面我們已經(jīng)介紹了java.lang包下的幾個基本Annotation了。在JDK中除了java.lang包下有Annotation,在java.lang.annotation下也有幾個常用的元Annotation。
在annotation包下的好幾個元Annotation都是用于修飾其他的Annotation定義。
5.1@Retention上面在將注解信息注入到方法中的時候,我們最后加上了@Retention的注解....不然就會報錯了..那它是干什么用的呢?
@Retention只能用于修飾其他的Annotation,用于指定被修飾的Annotation被保留多長時間。
@Retention 包含了一個RetentionPolicy類型的value變量,所以在使用它的時候,必須要為value成員變量賦值
value變量的值只有三個:
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME }
java文件有三個時期:編譯,class,運行。@Retention默認是class
前面我們是使用反射來得到注解上的信息的,因為@Retention默認是class,而反射是在運行時期來獲取信息的。因此就獲取不到Annotation的信息了。于是,就得在自定義注解上修改它的RetentionPolicy值
5.2@Target@Target也是只能用于修飾另外的Annotation,它用于指定被修飾的Annotation用于修飾哪些程序單元
@Target是只有一個value成員變量的,該成員變量的值是以下的:
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE }
如果@Target指定的是ElementType.ANNOTATION_TYPE,那么該被修飾的Annotation只能修飾Annotaion
5.3@Documented@Documented用于指定被該Annotation修飾的Annotation類將被javadoc工具提取成文檔。
該元Annotation用得挺少的....
5.4@Inherited@Inherited也是用來修飾其他的Annotation的,被修飾過的Annotation將具有繼承性。。。
例子:
@xxx是我自定義的注解,我現(xiàn)在使用@xxx注解在Base類上使用....
使用@Inherited修飾@xxx注解
當(dāng)有類繼承了Base類的時候,該實現(xiàn)類自動擁有@xxx注解
六、注入對象到方法或成員變量上 6.1把對象注入到方法上前面我們已經(jīng)可以使用注解將基本的信息注入到方法上了,現(xiàn)在我們要使用的是將對象注入到方法上.....
上邊已經(jīng)說過了,注解上只能定義String、枚舉類、Double之類的成員變量,那怎么把對象注入到方法上呢?
6.1.2模擬場景:Person類,定義username和age屬性,擁有uername和age的getter和setter方法
public class Person { private String username; private int age; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
PersonDao類,PersonDao類定義了Person對象,擁有person的setter和getter方法
public class PersonDao { private Person person; public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } }
現(xiàn)在我要做的就是:使用注解將Person對象注入到setPerson()方法中,從而設(shè)置了PersonDao類的person屬性
public class PersonDao { private Person person; public Person getPerson() { return person; } //將username為zhongfucheng,age為20的Person對象注入到setPerson方法中 @InjectPerson(username = "zhongfucheng",age = 20) public void setPerson(Person person) { this.person = person; } }
步驟:
①: 自定義一個注解,屬性是和JavaBean類一致的
//注入工具是通過反射來得到注解的信息的,于是保留域必須使用RunTime @Retention(RetentionPolicy.RUNTIME) public @interface InjectPerson { String username(); int age(); }
②:編寫注入工具
//1.使用內(nèi)省【后邊需要得到屬性的寫方法】,得到想要注入的屬性 PropertyDescriptor descriptor = new PropertyDescriptor("person", PersonDao.class); //2.得到要想注入屬性的具體對象 Person person = (Person) descriptor.getPropertyType().newInstance(); //3.得到該屬性的寫方法【setPerson()】 Method method = descriptor.getWriteMethod(); //4.得到寫方法的注解 Annotation annotation = method.getAnnotation(InjectPerson.class); //5.得到注解上的信息【注解的成員變量就是用方法來定義的】 Method[] methods = annotation.getClass().getMethods(); //6.將注解上的信息填充到person對象上 for (Method m : methods) { //得到注解上屬性的名字【age或name】 String name = m.getName(); //看看Person對象有沒有與之對應(yīng)的方法【setAge(),setName()】 try { //6.1這里假設(shè):有與之對應(yīng)的寫方法,得到寫方法 PropertyDescriptor descriptor1 = new PropertyDescriptor(name, Person.class); Method method1 = descriptor1.getWriteMethod();//setAge(), setName() //得到注解中的值 Object o = m.invoke(annotation, null); //調(diào)用Person對象的setter方法,將注解上的值設(shè)置進去 method1.invoke(person, o); } catch (Exception e) { //6.2 Person對象沒有與之對應(yīng)的方法,會跳到catch來。我們要讓它繼續(xù)遍歷注解就好了 continue; } } //當(dāng)程序遍歷完之后,person對象已經(jīng)填充完數(shù)據(jù)了 //7.將person對象賦給PersonDao【通過寫方法】 PersonDao personDao = new PersonDao(); method.invoke(personDao, person); System.out.println(personDao.getPerson().getUsername()); System.out.println(personDao.getPerson().getAge());
③:總結(jié)一下步驟
其實我們是這樣把對象注入到方法中的:
得到想要類中注入的屬性
得到該屬性的對象
得到屬性對應(yīng)的寫方法
通過寫方法得到注解
獲取注解詳細的信息
將注解的信息注入到對象上
調(diào)用屬性寫方法,將已填充數(shù)據(jù)的對象注入到方法中
6.2把對象注入到成員變量上面已經(jīng)說了如何將對象注入到方法上了,那么注入到成員變量上也是非常簡單的。
步驟:
①:在成員變量上使用注解
public class PersonDao { @InjectPerson(username = "zhongfucheng",age = 20) private Person person; public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } }
②:編寫注入工具
//1.得到想要注入的屬性 Field field = PersonDao.class.getDeclaredField("person"); //2.得到屬性的具體對象 Person person = (Person) field.getType().newInstance(); //3.得到屬性上的注解 Annotation annotation = field.getAnnotation(InjectPerson.class); //4.得到注解的屬性【注解上的屬性使用方法來表示的】 Method[] methods = annotation.getClass().getMethods(); //5.將注入的屬性填充到person對象上 for (Method method : methods) { //5.1得到注解屬性的名字 String name = method.getName(); //查看一下Person對象上有沒有與之對應(yīng)的寫方法 try { //如果有 PropertyDescriptor descriptor = new PropertyDescriptor(name, Person.class); //得到Person對象上的寫方法 Method method1 = descriptor.getWriteMethod(); //得到注解上的值 Object o = method.invoke(annotation, null); //填充person對象 method1.invoke(person, o); } catch (IntrospectionException e) { //如果沒有想對應(yīng)的屬性,繼續(xù)循環(huán) continue; } } //循環(huán)完之后,person就已經(jīng)填充好數(shù)據(jù)了 //6.把person對象設(shè)置到PersonDao中 PersonDao personDao = new PersonDao(); field.setAccessible(true); field.set(personDao, person); System.out.println(personDao.getPerson().getUsername());七、總結(jié)
①:注入對象的步驟:得到想要注入的對象屬性,通過屬性得到注解的信息,通過屬性的寫方法將注解的信息注入到對象上,最后將對象賦給類。
②:注解其實就是兩個作用:
讓編譯器檢查代碼
將數(shù)據(jù)注入到方法、成員變量、類上
③:在JDK中注解分為了
基本Annotation
在lang包下,用于常用于標(biāo)記該方法,抑制編譯器警告等
元Annotaion
在annotaion包下,常用于修飾其他的Annotation定義
如果文章有錯的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號:Java3y
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/68912.html
摘要:開啟自動配置功能后文詳解這個注解,學(xué)過的同學(xué)應(yīng)該對它不會陌生,就是掃描注解,默認是掃描當(dāng)前類下的。簡單來說,這個注解可以幫助我們自動載入應(yīng)用程序所需要的所有默認配置。簡單理解這二者掃描的對象是不一樣的。 前言 只有光頭才能變強。 文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/ZhongFuCheng3y/3y 回顧前面Spring的文章(以學(xué)習(xí)...
摘要:是一種特殊的增強切面切面由切點和增強通知組成,它既包括了橫切邏輯的定義也包括了連接點的定義。實際上,一個的實現(xiàn)被拆分到多個類中在中聲明切面我們知道注解很方便,但是,要想使用注解的方式使用就必須要有源碼因為我們要 前言 只有光頭才能變強 上一篇已經(jīng)講解了Spring IOC知識點一網(wǎng)打盡!,這篇主要是講解Spring的AOP模塊~ 之前我已經(jīng)寫過一篇關(guān)于AOP的文章了,那篇把比較重要的知...
摘要:啟動原理和執(zhí)行原理分析一的啟動原理我們打開,注意看下面兩個依賴我們第一步是繼承了父項目,然后在添加啟動器的依賴,項目就會自動給我們導(dǎo)入關(guān)于項目所需要的配置和。 上一篇我們看到,我們很輕松的完成了項目的構(gòu)建,那么SpringBoot是如何做到的呢,在使用的使用又有哪些通用配置和注意事項呢? 其實SpringBoot給我們做了大量的自動配置功能,我們只需要引入對應(yīng)的啟動器就可以直接使用,作...
摘要:如果說要使用數(shù)據(jù)校驗,我十分相信小伙伴們都能夠使用,但估計大都是有個前提的環(huán)境。具體使用可參考小家讓支持對平鋪參數(shù)執(zhí)行數(shù)據(jù)校驗?zāi)J使用只能對進行校驗級聯(lián)校驗什么叫級聯(lián)校驗,其實就是帶校驗的成員里存在級聯(lián)對象時,也要對它完成校驗。 每篇一句 NBA里有兩大笑話:一是科比沒天賦,二是詹姆斯沒技術(shù) 相關(guān)閱讀 【小家Java】深入了解數(shù)據(jù)校驗:Java Bean Validation 2.0(...
閱讀 1355·2021-09-28 09:43
閱讀 4148·2021-09-04 16:41
閱讀 1924·2019-08-30 15:44
閱讀 3734·2019-08-30 15:43
閱讀 782·2019-08-30 14:21
閱讀 2041·2019-08-30 11:00
閱讀 3325·2019-08-29 16:20
閱讀 1928·2019-08-29 14:21