這篇文章跟大家分析一下“Java高級(jí)特性中的泛型、反射和注解該如何理解”。內(nèi)容詳細(xì)易懂,對(duì)“Java高級(jí)特性中的泛型、反射和注解該如何理解”感興趣的朋友可以跟著小編的思路慢慢深入來(lái)閱讀一下,希望閱讀后能夠?qū)Υ蠹矣兴鶐椭O旅娓【幰黄鹕钊雽W(xué)習(xí)“Java高級(jí)特性中的泛型、反射和注解該如何理解”的知識(shí)吧。
目前創(chuàng)新互聯(lián)已為成百上千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、網(wǎng)站運(yùn)營(yíng)、企業(yè)網(wǎng)站設(shè)計(jì)、泰州網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶(hù)導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶(hù)和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
一、泛型介紹
在日常編程的過(guò)程中,泛型在這三個(gè)特性之中使用頻率是最高的。”泛型”一詞中的泛字可以理解為泛化的意思,即由具體的、個(gè)別的擴(kuò)大為一般的。Oracle對(duì)泛型的官方定義是:泛型類(lèi)型是通過(guò)類(lèi)型參數(shù)化的泛型類(lèi)或接口。一言以蔽之,泛型就是通過(guò)類(lèi)型參數(shù)化,來(lái)解決程序的通用性設(shè)計(jì)和實(shí)現(xiàn)的若干問(wèn)題。
Java泛型是1.5版本后引入的特性,它主要被用于解決三類(lèi)問(wèn)題:
1、編譯器類(lèi)型檢查

例如上圖中的實(shí)例1設(shè)計(jì)了一個(gè)簡(jiǎn)單的Box類(lèi),在其中定義了一個(gè)private的object的屬性,同時(shí)定義了get()和set()兩個(gè)行為,其中set()用于保存object到Box內(nèi),set()用于獲取Box中的object對(duì)象。從抽象的角度看,Box類(lèi)抽象了一個(gè)用于在盒子中存放物品對(duì)象和存取的行為,存取的方法接受或者返回Object類(lèi)型的對(duì)象。在這個(gè)抽象的基礎(chǔ)上,可以存放除原始類(lèi)型外任意類(lèi)型的對(duì)象,Object類(lèi)型的聲明體現(xiàn)了面向?qū)ο笾欣^承的理念。
在實(shí)例2中,實(shí)現(xiàn)了不同業(yè)務(wù)場(chǎng)景下對(duì)Box的使用方式。其中列舉了兩種不同的業(yè)務(wù)場(chǎng)景,場(chǎng)景一需要在Box中存放String類(lèi)型的對(duì)象,場(chǎng)景二需要在Box中存放Integer類(lèi)型的對(duì)象,這種情況下,在實(shí)際開(kāi)發(fā)時(shí),場(chǎng)景二中很有可能會(huì)錯(cuò)誤地傳入一個(gè)String對(duì)象,導(dǎo)致運(yùn)行時(shí)錯(cuò)誤的發(fā)生,而這正是因?yàn)锽ox可以被只有傳入任意類(lèi)型的對(duì)象導(dǎo)致的,這種情況在集合類(lèi)操作時(shí)尤為突出。例如實(shí)例3中的情況:
首先聲明了一個(gè)List類(lèi)型的boxes對(duì)象,其中存放了兩個(gè)對(duì)象,一個(gè)是String類(lèi)型的“aaaaa”,另一個(gè)是Integer類(lèi)型的11111。在業(yè)務(wù)場(chǎng)景一下,使用者認(rèn)為boxes中存放的所有對(duì)象都是String類(lèi)型的,因此在取出第二個(gè)對(duì)象并進(jìn)行類(lèi)型轉(zhuǎn)換的時(shí)候就發(fā)生了錯(cuò)誤。這種情況往往讓使用者十分迷惑,明明編譯時(shí)沒(méi)有問(wèn)題,但是在運(yùn)行時(shí)卻產(chǎn)生了異常。也就是說(shuō),在這種面向?qū)ο蟮某橄筮^(guò)程中,無(wú)法通過(guò)編譯來(lái)驗(yàn)證類(lèi)型該如何進(jìn)行使用。
那么泛型是如何解決這類(lèi)問(wèn)題的呢?

Oracle意識(shí)到了上述的問(wèn)題,在引入泛型之后,通過(guò)將代碼中的“public class Box”更改為“public class Box<T>”來(lái)創(chuàng)建泛型類(lèi)型的聲明,而這個(gè)聲明的背后實(shí)質(zhì)上是引入了可以在類(lèi)中任何地方使用的類(lèi)型變量T。如實(shí)例4中所示:可以看到,除了新增的泛型類(lèi)型聲明<T>外,所有在原來(lái)代碼中出現(xiàn)的Object都被類(lèi)型變量T所替換。
乍一看類(lèi)型變量這個(gè)詞,感覺(jué)有點(diǎn)晦澀難懂,但其實(shí)如果仔細(xì)思量一番會(huì)發(fā)現(xiàn)它其實(shí)并不難理解,上面的實(shí)例4可以理解為“在使用泛型時(shí),可以將類(lèi)型參數(shù)T傳遞給Box類(lèi)型本身”,結(jié)合Oracle給出的官方定義“泛型的本質(zhì)是類(lèi)型參數(shù)化”會(huì)有更深的理解。
在實(shí)例5中,在對(duì)象聲明和初始化的時(shí)候,都指定了類(lèi)型參數(shù)T,在場(chǎng)景一種,T為String;在場(chǎng)景二中,T為Integer。這樣,在場(chǎng)景二中向IntegerBox中傳入String類(lèi)型的數(shù)據(jù)“aaaaa”時(shí),程序會(huì)報(bào)錯(cuò)。實(shí)例6中的泛型集合對(duì)象的操作也與之類(lèi)似,在聲明了一個(gè)List<String>的boxes對(duì)象之后,如果向boxes中傳入Integer對(duì)象11111,程序會(huì)報(bào)錯(cuò)。
可以看到,通過(guò)對(duì)于泛型的使用,之前的多業(yè)務(wù)場(chǎng)景中的問(wèn)題都得到了解決,因?yàn)楝F(xiàn)在在編譯階段就可以解決之前類(lèi)型不匹配的問(wèn)題,而不用等到運(yùn)行時(shí)才暴露問(wèn)題,只要合理使用泛型,就能在很大程度上規(guī)避此類(lèi)風(fēng)險(xiǎn)。對(duì)于泛型的使用,這種參數(shù)化類(lèi)型的作用表面上看是聲明,背后其實(shí)是約定。
2、強(qiáng)制類(lèi)型轉(zhuǎn)換

再回顧一下實(shí)例3,在List類(lèi)型的boxes對(duì)象中存放了兩個(gè)對(duì)象,分別是String類(lèi)型的“aaaaa”和Integer類(lèi)型的11111。其中存在一個(gè)問(wèn)題,在對(duì)于boxes的聲明中,使用者不知道boxes的list中到底應(yīng)該存放什么類(lèi)型的對(duì)象,而編譯器也不知道集合存放的數(shù)據(jù)類(lèi)型,只能通過(guò)實(shí)際的業(yè)務(wù)場(chǎng)景來(lái)決定這個(gè)box是什么類(lèi)型,采用將Object強(qiáng)制轉(zhuǎn)換成String的方式,來(lái)達(dá)到業(yè)務(wù)要求的效果。
在使用泛型之后,解決了這種場(chǎng)景下必須進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換的問(wèn)題。如實(shí)例7中,通過(guò)泛型聲明,指定集合內(nèi)元素的類(lèi)型參數(shù)為String類(lèi)型,這樣編譯器就直接知曉了元素的類(lèi)型,而無(wú)需依靠實(shí)際的業(yè)務(wù)邏輯進(jìn)行轉(zhuǎn)換,從而解決了這類(lèi)類(lèi)型強(qiáng)制轉(zhuǎn)換的問(wèn)題。
3、可讀性和靈活性

泛型除了能進(jìn)行編譯器類(lèi)型檢查和規(guī)避類(lèi)型強(qiáng)制轉(zhuǎn)換外,還能有效地提高代碼的可讀性。對(duì)于實(shí)例3,如果不使用泛型,當(dāng)一個(gè)不清楚業(yè)務(wù)場(chǎng)景的人在對(duì)集合進(jìn)行操作時(shí),無(wú)法知道list中存儲(chǔ)的是什么類(lèi)型的對(duì)象,如果使用了泛型,就能夠通過(guò)其類(lèi)型參數(shù)判斷出當(dāng)前的業(yè)務(wù)場(chǎng)景,也增加了代碼的可讀性,同時(shí)也可以大膽地在抽象繼承的基礎(chǔ)上進(jìn)行開(kāi)發(fā)了。
泛型使用上的靈活性體現(xiàn)在很多方面,因?yàn)樗旧韺?shí)質(zhì)上就是對(duì)于繼承在使用上的一種增強(qiáng)。因?yàn)榉盒驮诰唧w工作時(shí),當(dāng)編譯器在編譯源碼的時(shí)候,首先要進(jìn)行泛型類(lèi)型參數(shù)的檢查,檢查出類(lèi)型不匹配等問(wèn)題,然后進(jìn)行類(lèi)型擦除并同時(shí)在類(lèi)型參數(shù)出現(xiàn)的位置插入強(qiáng)制轉(zhuǎn)換指令,從而實(shí)現(xiàn)泛型。
除了上述的基礎(chǔ)用法之外,泛型還有幾種特殊的高階用法:

通配符的設(shè)計(jì)存在一定的場(chǎng)景,例如在使用泛型后,首先聲明了一個(gè)Animal的類(lèi),而后聲明了一個(gè)繼承自Animal類(lèi)的Cat類(lèi),顯然Cat類(lèi)是Animal類(lèi)的子類(lèi),但是List<Cat>卻不是List<Animal>的子類(lèi)型,而在程序中往往需要表達(dá)這樣的邏輯關(guān)系。為了解決這種類(lèi)似的場(chǎng)景,在泛型的參數(shù)類(lèi)型的基礎(chǔ)上新增了通配符的用法,具體來(lái)說(shuō)有三種用法:<? extends T>、<? super T>、<?>。其中前兩者被稱(chēng)為限定通配符,<?>被稱(chēng)為非限定通配符。
1、<? extends T> 上界通配符
上界通配符顧名思義,<? extends T>表示的是類(lèi)型的上界(包含自身),因此通配的參數(shù)化類(lèi)型可能是T或T的子類(lèi)。正因?yàn)闊o(wú)法確定具體的類(lèi)型是什么,add方法受限(可以添加null,因?yàn)閚ull表示任何類(lèi)型),但可以從列表中獲取元素后賦值給父類(lèi)型。如上圖中的第一個(gè)例子,第三個(gè)add()操作會(huì)受限,原因在于List<Animal>和List<Cat>是List<? extends Animal>的子類(lèi)型。
2、<? super T> 下界通配符
下界通配符<? super T>表示的是參數(shù)化類(lèi)型是T的超類(lèi)型(包含自身),層層至上,直至Object,編譯器無(wú)從判斷get()返回的對(duì)象的類(lèi)型是什么,因此get()方法受限。但是可以進(jìn)行add()方法,add()方法可以添加T類(lèi)型和T類(lèi)型的子類(lèi)型,如第二個(gè)例子中首先添加了一個(gè)Cat類(lèi)型對(duì)象,然后添加了兩個(gè)Cat子類(lèi)類(lèi)型的對(duì)象,這種方法是可行的,但是如果添加一個(gè)Animal類(lèi)型的對(duì)象,顯然將繼承的關(guān)系弄反了,是不可行的。
3、<?> 無(wú)界通配符
在理解了上界通配符和下界通配符之后,其實(shí)也自然而然的理解了無(wú)界通配符。無(wú)界通配符用<?>表示,?代表了任何的一種類(lèi)型,能代表任何一種類(lèi)型的只有null(Object本身也算是一種類(lèi)型,但卻不能代表任何一種類(lèi)型,所以List<Object>和List<null>的含義是不同的,前者類(lèi)型是Object,也就是繼承樹(shù)的最上層,而后者的類(lèi)型完全是未知的)。
二、反射機(jī)制
反射是Java語(yǔ)言本身具備的一個(gè)重要的動(dòng)態(tài)機(jī)制。用一句話(huà)來(lái)解釋反射的定義:自控制,自描述。即通過(guò)反射可以動(dòng)態(tài)的獲取類(lèi)、屬性、方法的信息,也能構(gòu)造對(duì)象并控制對(duì)象的屬性和行為。

上圖中有一個(gè)Apple類(lèi),它有兩個(gè)構(gòu)造器、一個(gè)屬性和get()、set()兩個(gè)行為。在左側(cè)的“自描述”中主要是嘗試在動(dòng)態(tài)的過(guò)程中借助反射獲取Apple類(lèi)的構(gòu)造器信息和對(duì)應(yīng)的參數(shù)個(gè)數(shù)、類(lèi)的屬性信息和類(lèi)的方法信息。其中有一個(gè)Class類(lèi)型,它可以產(chǎn)生Class對(duì)象被ClassLoader加載,從而在jvm中實(shí)現(xiàn)對(duì)它的調(diào)用。在這段程序中,打印了一些類(lèi)的信息、類(lèi)的屬性信息和類(lèi)的方法信息。在右側(cè)的“自控制”的代碼中,實(shí)現(xiàn)了在運(yùn)行的過(guò)程中創(chuàng)建了一些對(duì)象并觸發(fā)這個(gè)對(duì)象的一些行為,最后還嘗試對(duì)對(duì)象的屬性進(jìn)行賦值。反射的基本使用方法較為簡(jiǎn)單,但是這種機(jī)制卻增強(qiáng)了Java語(yǔ)言的靈活性。

如上圖所示,非反射的Java類(lèi)的大致運(yùn)行流程是:編寫(xiě)源文件Apple.java,然后編譯器將其編譯成字節(jié)碼文件Apple.class,最后加載到j(luò)vm中并運(yùn)行。而采用反射的方式時(shí),編譯器一開(kāi)始對(duì)其類(lèi)型(編譯類(lèi)型和動(dòng)態(tài)類(lèi)型)是一無(wú)所知的,只有在運(yùn)行過(guò)后,編譯器才知道其真正的類(lèi)型。
反射的優(yōu)勢(shì)主要在于兩點(diǎn):
在一些場(chǎng)景中,這種“未知類(lèi)型”實(shí)際上大大增強(qiáng)了程序運(yùn)行時(shí)的靈活性,但是其性能會(huì)有一些損耗;
對(duì)于對(duì)象的類(lèi)型可以在運(yùn)行時(shí)判斷,這樣的特性實(shí)質(zhì)上是對(duì)多態(tài)極大地增強(qiáng),進(jìn)一步地將上層的抽象與下層的具體實(shí)現(xiàn)進(jìn)行解耦。
這兩點(diǎn)在JDBC Driver中體現(xiàn)的非常明顯,例如上圖中的實(shí)例中,JDBC的驅(qū)動(dòng)加載方式是通過(guò)反射機(jī)制實(shí)現(xiàn)的,從而保證運(yùn)行時(shí)可以動(dòng)態(tài)選擇要加載的驅(qū)動(dòng)程序,程序靈活性大大增強(qiáng)。另外,JDBC只是設(shè)計(jì)了驅(qū)動(dòng)需要實(shí)現(xiàn)的接口,并不關(guān)心驅(qū)動(dòng)廠商的個(gè)數(shù)和實(shí)現(xiàn)方式,只要安裝統(tǒng)一的規(guī)范即可,至于類(lèi)型的判斷和具體方法的觸發(fā),交給運(yùn)行期動(dòng)態(tài)判斷即可,這種反射機(jī)制的使用淋漓盡致的體現(xiàn)了多態(tài),并且降低了類(lèi)與類(lèi)之間的耦合度。
三、注解的使用
注解是在1.5版本引入的,現(xiàn)在已經(jīng)成為日常程序開(kāi)發(fā)中非常重要的一部分。注解是一種元數(shù)據(jù),本身沒(méi)有任何作用,如果要有,必須依附在具體的對(duì)象上,在日常使用中最常見(jiàn)的兩個(gè)注解是@Override和@Deprecated。
先不考慮注解具體的概念、用法和如何工作等問(wèn)題,注解與“標(biāo)簽”的概念十分相似,@Override可以理解為在方法上添加了一個(gè)標(biāo)簽,其代表的就是“這是一個(gè)繼承關(guān)系中,子類(lèi)已經(jīng)重寫(xiě)的方法。”更進(jìn)一步理解,這個(gè)標(biāo)簽在某個(gè)方法上加上之后,如果父類(lèi)中沒(méi)有該方法,那么在編譯的時(shí)候就會(huì)報(bào)錯(cuò),而且可以解決在繼承場(chǎng)景下一些不留心將方法名拼錯(cuò)的情況,同時(shí)增強(qiáng)了一些程序的可讀性。

如上圖所示,同樣以@Override為例,對(duì)注解進(jìn)行進(jìn)一步的提取和抽象。具體抽象出了四個(gè)方面:首先在作用域方面,它只能作用于子類(lèi)重寫(xiě)的方法上;其次在生命周期方面,注解只是在編譯時(shí)進(jìn)行檢查,在編譯結(jié)束后便沒(méi)有了任何作用;除此之外,在文檔支持方面,為例解決可讀性的問(wèn)題,設(shè)計(jì)了@Documented的注解,用來(lái)表示注解的說(shuō)明注釋是否包含在JavaDoc中;在層級(jí)結(jié)構(gòu)設(shè)計(jì)方面,設(shè)計(jì)了@inherited用來(lái)表示注解是否可以被子類(lèi)繼承。
在上圖中定義了一個(gè)蘋(píng)果描述注解,包含了@Target、@Retention、@Inherited和@Documented四個(gè)注解,表示它生命周期是程序運(yùn)行的聲明周期、可以被子類(lèi)繼承、文檔可以被包含。在設(shè)計(jì)出這個(gè)注解之后,可以將其用在前文中的Apple實(shí)例上,如圖中在類(lèi)和方法上各添加了一個(gè)注解,在添加完后,便可以配合反射看到注解的效果,這樣可以更好的加強(qiáng)其自描述的能力和配置的靈活性。
關(guān)于Java高級(jí)特性中的泛型、反射和注解該如何理解就分享到這里啦,希望上述內(nèi)容能夠讓大家有所提升。如果想要學(xué)習(xí)更多知識(shí),請(qǐng)大家多多留意小編的更新。謝謝大家關(guān)注一下創(chuàng)新互聯(lián)網(wǎng)站!
本文標(biāo)題:Java高級(jí)特性中的泛型、反射和注解該如何理解
本文鏈接:http://chinadenli.net/article26/ppdecg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計(jì)、網(wǎng)站排名、標(biāo)簽優(yōu)化、品牌網(wǎng)站制作、網(wǎng)站維護(hù)、網(wǎng)站設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)