jdk50新特性介紹_第1頁
jdk50新特性介紹_第2頁
jdk50新特性介紹_第3頁
jdk50新特性介紹_第4頁
jdk50新特性介紹_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、jdk5 0新特性介紹jdk5.0新特性介紹2010-04-02 10:51Java 5.0發(fā)布了,許多人都將開始使用這個JDK版本的一些新增特性。從增強(qiáng)的for循環(huán)到諸如泛型(generic)之類更復(fù)雜的特性,都將很快出現(xiàn)在您所編寫的代碼中。我們剛剛完成了一個基于Java 5.0的大型任務(wù),而本文就是要介紹我們使用這些新特性的體驗。本文不是一篇入門性的文章,而是對這些特性以及它們所產(chǎn)生的影響的深入介紹,同時還給出了一些在項目中更有效地使用這些特性的技巧。簡介在JDK 1.5的beta階段,我們?yōu)锽EA的Java IDE開發(fā)了一個Java 5編譯器。因為我們實現(xiàn)了許多新特性,所以人們開始以新的

2、方式利用它們;有些用法很聰明,而有些用法明顯應(yīng)該被列入禁用清單。編譯器本身使用了新的語言特性,所以我們也獲得了使用這些特性維護(hù)代碼的直接體驗。本文將介紹其中的許多特性和使用它們的體驗。我們假定您已經(jīng)熟悉了這些新特性,所以不再全面介紹每個特性,而是談?wù)撘恍┯腥さ?、但很可能不太明顯的內(nèi)容和用法。這些技巧出自我們的實際體驗,并大致按照語言特性進(jìn)行了分類。我們將從最簡單的特性開始,逐步過渡到高級特性。泛型所包含的內(nèi)容特別豐富,因此占了本文一半的篇幅。增強(qiáng)的for循環(huán)為了迭代集合和數(shù)組,增強(qiáng)的for循環(huán)提供了一個簡單、兼容的語法。有兩點值得一提:Init表達(dá)式在循環(huán)中,初始化表達(dá)式只計算一次。這意味著您

3、通常可以移除一個變量聲明。在這個例子中,我們必須創(chuàng)建一個整型數(shù)組來保存computeNumbers()的結(jié)果,以防止每一次循環(huán)都重新計算該方法。您可以看到,下面的代碼要比上面的代碼整潔一些,并且沒有泄露變量numbers:未增強(qiáng)的For:int sum=0;Integer numbers=computeNumbers();for(int i=0;i numbers.length;i+)sum+=numbersi;增強(qiáng)后的For:int sum=0;for(int number:computeNumbers()sum+=number;局限性有時需要在迭代期間訪問迭代器或下標(biāo),看起來增強(qiáng)的for循

4、環(huán)應(yīng)該允許該操作,但事實上不是這樣,請看下面的例子:for(int i=0;i numbers.length;i+)if(i!=0)System.out.print(,);System.out.print(numbersi);我們希望將數(shù)組中的值打印為一個用逗號分隔的清單。我們需要知道目前是否是第一項,以便確定是否應(yīng)該打印逗號。使用增強(qiáng)的for循環(huán)是無法獲知這種信息的。我們需要自己保留一個下標(biāo)或一個布爾值來指示是否經(jīng)過了第一項。這是另一個例子:for(Iterator integer it=n.iterator();it.hasNext();)if(it.next()0)it.remove()

5、;在此例中,我們想從整數(shù)集合中刪除負(fù)數(shù)項。為此,需要對迭代器調(diào)用一個方法,但是當(dāng)使用增強(qiáng)的for循環(huán)時,迭代器對我們來說是看不到的。因此,我們只能使用Java 5之前版本的迭代方法。順便說一下,這里需要注意的是,由于Iterator是泛型,所以其聲明是Iterator Integer。許多人都忘記了這一點而使用了Iterator的原始格式。注釋注釋處理是一個很大的話題。因為本文只關(guān)注核心的語言特性,所以我們不打算涵蓋它所有的可能形式和陷阱。我們將討論內(nèi)置的注釋(SuppressWarnings,Deprecated和Override)以及一般注釋處理的局限性。Suppress Warnings

6、該注釋關(guān)閉了類或方法級別的編譯器警告。有時候您比編譯器更清楚地知道,代碼必須使用一個被否決的方法或執(zhí)行一些無法靜態(tài)確定是否類型安全的動作,而使用:SuppressWarnings(deprecation)public static void selfDestruct()Thread.currentThread().stop();這可能是內(nèi)置注釋最有用的地方。遺憾的是,1.5.0_04的javac不支持它。但是1.6支持它,并且Sun正在努力將其向后移植到1.5中。Eclipse 3.1中支持該注釋,其他IDE也可能支持它。這允許您把代碼徹底地從警告中解脫出來。如果在編譯時出現(xiàn)警告,可以確定是您

7、剛剛把它添加進(jìn)來-以幫助查看那些可能不安全的代碼。隨著泛型的添加,它使用起來將更趁手。Deprecated遺憾的是,Deprecated沒那么有用。它本來旨在替換deprecated javadoc標(biāo)簽,但是由于它不包含任何字段,所以也就沒有方法來建議deprecated類或方法的用戶應(yīng)該使用什么做為替代品。大多數(shù)用法都同時需要javadoc標(biāo)簽和這個注釋。Override Override表示,它所注釋的方法應(yīng)該重寫超類中具有相同簽名的方法:Override public int hashCode().看上面的例子,如果沒有在hashCode中將C大寫,在編譯時不會出現(xiàn)錯誤,但是在運行時將無

8、法像期望的那樣調(diào)用該方法。通過添加Override標(biāo)簽,編譯器會提示它是否真正地執(zhí)行了重寫。在超類發(fā)生改變的情況中,這也很有幫助。如果向該方法中添加一個新參數(shù),而且方法本身也被重命名了,那么子類將突然不能編譯,因為它不再重寫超類的任何東西。其它注釋注釋在其他場景中非常有用。當(dāng)不是直接修改行為而是增強(qiáng)行為時,特別是在添加樣板代碼的情況下,注釋在諸如EJB和Web services這樣的框架中運行得非常好。注釋不能用做預(yù)處理器。Sun的設(shè)計特別預(yù)防了完全因為注釋而修改類的字節(jié)碼。這樣可以正確地理解該語言的成果,而且IDE之類的工具也可以執(zhí)行深入的代碼分析和重構(gòu)之類的功能。注釋不是銀彈。第一次遇到的

9、時候,人們試圖嘗試各種技巧。請看下面這個從別人那里獲得的建議:public class FooProperty private int bar;其思想是為私有字段bar自動創(chuàng)建getter和setter方法。遺憾的是,這個想法有兩個失敗之處:1)它不能運行,2)它使代碼難以閱讀和處理。它是無法實現(xiàn)的,因為前面已經(jīng)提到了,Sun特別阻止了對出現(xiàn)注釋的類進(jìn)行修改。即使是可能的,它也不是一個好主意,因為它使代碼可讀性差。第一次看到這段代碼的人會不知道該注釋創(chuàng)建了方法。此外,如果將來您需要在這些方法內(nèi)部執(zhí)行一些操作,注釋也是沒用的??傊?,不要試圖用注釋去做那些常規(guī)代碼可以完成的事情。枚舉enum非常像

10、public static final int聲明,后者作為枚舉值已經(jīng)使用了很多年。對int所做的最大也是最明顯的改進(jìn)是類型安全-您不能錯誤地用枚舉的一種類型代替另一種類型,這一點和int不同,所有的int對編譯器來說都是一樣的。除去極少數(shù)例外的情況,通常都應(yīng)該用enum實例替換全部的枚舉風(fēng)格的int結(jié)構(gòu)。枚舉提供了一些附加的特性。EnumMap和EnumSet這兩個實用類是專門為枚舉優(yōu)化的標(biāo)準(zhǔn)集合實現(xiàn)。如果知道集合只包含枚舉類型,那么應(yīng)該使用這些專門的集合來代替HashMap或HashSet。大部分情況下,可以使用enum對代碼中的所有public static final int做插入替換

11、。它們是可比的,并且可以靜態(tài)導(dǎo)入,所以對它們的引用看起來是等同的,即使是對于內(nèi)部類(或內(nèi)部枚舉類型)。注意,比較枚舉類型的時候,聲明它們的指令表明了它們的順序值。隱藏的靜態(tài)方法兩個靜態(tài)方法出現(xiàn)在所有枚舉類型聲明中。因為它們是枚舉子類上的靜態(tài)方法,而不是Enum本身的方法,所以它們在java.lang.Enum的javadoc中沒有出現(xiàn)。第一個是values(),返回一個枚舉類型所有可能值的數(shù)組。第二個是valueOf(),為提供的字符串返回一個枚舉類型,該枚舉類型必須精確地匹配源代碼聲明。方法關(guān)于枚舉類型,我們最喜歡的一個方面是它可以有方法。過去您可能需要編寫一些代碼,對public stat

12、ic final int進(jìn)行轉(zhuǎn)換,把它從數(shù)據(jù)庫類型轉(zhuǎn)換為JDBC URL。而現(xiàn)在則可以讓枚舉類型本身帶一個整理代碼的方法。下面就是一個例子,包括DatabaseType枚舉類型的抽象方法以及每個枚舉實例中提供的實現(xiàn):public enum DatabaseTypeORACLEpublic String getJdbcUrl().,MYSQLpublic String getJdbcUrl().;public abstract String getJdbcUrl();現(xiàn)在枚舉類型可以直接提供它的實用方法。例如:DatabaseType dbType=.;String jdbcURL=dbType

13、.getJdbcUrl();要獲取URL,必須預(yù)先知道該實用方法在哪里??勺儏?shù)(Vararg)正確地使用可變參數(shù)確實可以清理一些垃圾代碼。典型的例子是一個帶有可變的String參數(shù)個數(shù)的log方法:Log.log(String code)Log.log(String code,String arg)Log.log(String code,String arg1,String arg2)Log.log(String code,String args)當(dāng)討論可變參數(shù)時,比較有趣的是,如果用新的可變參數(shù)替換前四個例子,將是兼容的:Log.log(String code,String.args)所有

14、的可變參數(shù)都是源兼容的-那就是說,如果重新編譯log()方法的所有調(diào)用程序,可以直接替換全部的四個方法。然而,如果需要向后的二進(jìn)制兼容性,那么就需要舍去前三個方法。只有最后那個帶一個字符串?dāng)?shù)組參數(shù)的方法等效于可變參數(shù)版本,因此可以被可變參數(shù)版本替換。類型強(qiáng)制轉(zhuǎn)換如果希望調(diào)用程序了解應(yīng)該使用哪種類型的參數(shù),那么應(yīng)該避免用可變參數(shù)進(jìn)行類型強(qiáng)制轉(zhuǎn)換??聪旅孢@個例子,第一項希望是String,第二項希望是Exception:Log.log(Object.objects)String message=(String)objects0;if(objects.length 1)Exception e=(Ex

15、ception)objects1;/Do something with the exception方法簽名應(yīng)該如下所示,相應(yīng)的可變參數(shù)分別使用String和Exception聲明:Log.log(String message,Exception e,Object.objects).不要使用可變參數(shù)破壞類型系統(tǒng)。需要強(qiáng)類型化時才可以使用它。對于這個規(guī)則,PrintStream.printf()是一個有趣的例外:它提供類型信息作為自己的第一個參數(shù),以便稍后可以接受那些類型。協(xié)變返回協(xié)變返回的基本用法是用于在已知一個實現(xiàn)的返回類型比API更具體的時候避免進(jìn)行類型強(qiáng)制轉(zhuǎn)換。在下面這個例子中,有一個返回

16、Animal對象的Zoo接口。我們的實現(xiàn)返回一個AnimalImpl對象,但是在JDK 1.5之前,要返回一個Animal對象就必須聲明。:public interface Zoopublic Animal getAnimal();public class ZooImpl implements Zoopublic Animal getAnimal()return new AnimalImpl();協(xié)變返回的使用替換了三個反模式:直接字段訪問。為了規(guī)避API限制,一些實現(xiàn)把子類直接暴露為字段:ZooImpl._animal另一種形式是,在知道實現(xiàn)的實際上是特定的子類的情況下,在調(diào)用程序中執(zhí)行向下

17、轉(zhuǎn)換:(AnimalImpl)ZooImpl.getAnimal().implMethod();我看到的最后一種形式是一個具體的方法,該方法用來避免由一個完全不同的簽名所引發(fā)的問題:ZooImpl._getAnimal();這三種模式都有它們的問題和局限性。要么是不夠整潔,要么就是暴露了不必要的實現(xiàn)細(xì)節(jié)。協(xié)變協(xié)變返回模式就比較整潔、安全并且易于維護(hù),它也不需要類型強(qiáng)制轉(zhuǎn)換或特定的方法或字段:public AnimalImpl getAnimal()return new AnimalImpl();使用結(jié)果:ZooImpl.getAnimal().implMethod();使用泛型我們將從兩個角度

18、來了解泛型:使用泛型和構(gòu)造泛型。我們不討論List、Set和Map的顯而易見的用法。知道泛型集合是強(qiáng)大的并且應(yīng)該經(jīng)常使用就足夠了。我們將討論泛型方法的使用以及編譯器推斷類型的方法。通常這些都不會出問題,但是當(dāng)出問題時,錯誤信息會非常令人費解,所以需要了解如何修復(fù)這些問題。泛型方法除了泛型類型,Java 5還引入了泛型方法。在這個來自java.util.Collections的例子中,構(gòu)造了一個單元素列表。新的List的元素類型是根據(jù)傳入方法的對象的類型來推斷的:static TList TCollections.singletonList(T o)示例用法:public List Intege

19、r getListOfOne()return Collections.singletonList(1);在示例用法中,我們傳入了一個int。所以方法的返回類型就是List Integer。編譯器把T推斷為Integer。這和泛型類型是不同的,因為您通常不需要顯式地指定類型參數(shù)。這也顯示了自動裝箱和泛型的相互作用。類型參數(shù)必須是引用類型:這就是為什么我們得到的是List Integer而不是List int。不帶參數(shù)的泛型方法emptyList()方法與泛型一起引入,作為java.util.Collections中EMPTY_LIST字段的類型安全置換:static TList TCollect

20、ions.emptyList()示例用法:public List Integer getNoIntegers()return Collections.emptyList();與先前的例子不同,這個方法沒有參數(shù),那么編譯器如何推斷T的類型呢?基本上,它將嘗試使用一次參數(shù)。如果沒有起作用,它再次嘗試使用返回或賦值類型。在本例中,返回的是List Integer,所以T被推斷為Integer。如果在返回語句或賦值語句之外的位置調(diào)用泛型方法會怎么樣呢?那么編譯器將無法執(zhí)行類型推斷的第二次傳送。在下面這個例子中,emptyList()是從條件運算符內(nèi)部調(diào)用的:public List Integer ge

21、tNoIntegers()return x?Collections.emptyList():null;因為編譯器看不到返回上下文,也不能推斷T,所以它放棄并采用Object。您將看到一個錯誤消息,比如:無法將List Object轉(zhuǎn)換為List Integer。為了修復(fù)這個錯誤,應(yīng)顯式地向方法調(diào)用傳遞類型參數(shù)。這樣,編譯器就不會試圖推斷類型參數(shù),就可以獲得正確的結(jié)果:return x?Collections.Integer emptyList():null;這種情況經(jīng)常發(fā)生的另一個地方是在方法調(diào)用中。如果一個方法帶一個List String參數(shù),并且需要為那個參數(shù)調(diào)用這個傳遞的emptyLis

22、t(),那么也需要使用這個語法。集合之外這里有三個泛型類型的例子,它們不是集合,而是以一種新穎的方式使用泛型。這三個例子都來自標(biāo)準(zhǔn)的Java庫:Class TClass在類的類型上被參數(shù)化了。這就使無需類型強(qiáng)制轉(zhuǎn)換而構(gòu)造一個newInstance成為可能。Comparable TComparable被實際的比較類型參數(shù)化。這就在compareTo()調(diào)用時提供了更強(qiáng)的類型化。例如,String實現(xiàn)Comparable String。對除String之外的任何東西調(diào)用compareTo(),都會在編譯時失敗。Enum Eextends Enum EEnum被枚舉類型參數(shù)化。一個名為Color的枚

23、舉類型將擴(kuò)展Enum Color。getDeclaringClass()方法返回枚舉類型的類對象,在這個例子中就是一個Color對象。它與getClass()不同,后者可能返回一個無名類。通配符泛型最復(fù)雜的部分是對通配符的理解。我們將討論三種類型的通配符以及它們的用途。首先讓我們了解一下數(shù)組是如何工作的??梢詮囊粋€Integer為一個Number賦值。如果嘗試把一個Float寫到Number中,那么可以編譯,但在運行時會失敗,出現(xiàn)一個ArrayStoreException:Integer ia=new Integer5;Number na=ia;na0=0.5;/compiles,but fa

24、ils at runtime如果試圖把該例直接轉(zhuǎn)換成泛型,那么會在編譯時失敗,因為賦值是不被允許的:List Integer iList=new ArrayList Integer();List Number nList=iList;/not allowed nList.add(0.5);如果使用泛型,只要代碼在編譯時沒有出現(xiàn)警告,就不會遇到運行時ClassCastException。上限通配符我們想要的是一個確切元素類型未知的列表,這一點與數(shù)組是不同的。List Number是一個列表,其元素類型是具體類型Number。List?extends Number是一個確切元素類型未知的列表。它是

25、Number或其子類型。上限如果我們更新初始的例子,并賦值給List?extends Number,那么現(xiàn)在賦值就會成功了:List Integer iList=new ArrayList Integer();List?extends Number nList=iList;Number n=nList.get(0);nList.add(0.5);/Not allowed我們可以從列表中得到Number,因為無論列表的確切元素類型是什么(Float、Integer或Number),我們都可以把它賦值給Number。我們?nèi)匀徊荒馨迅↑c類型插入列表中。這會在編譯時失敗,因為我們不能證明這是安全的。如

26、果我們想要向列表中添加浮點類型,它將破壞iList的初始類型安全-它只存儲Integer。通配符給了我們比數(shù)組更多的表達(dá)能力。為什么使用通配符在下面這個例子中,通配符用于向API的用戶隱藏類型信息。在內(nèi)部,Set被存儲為CustomerImpl。而API的用戶只知道他們正在獲取一個Set,從中可以讀取Customer。此處通配符是必需的,因為無法從Set CustomerImpl向Set Customer賦值:public class CustomerFactoryprivate Set CustomerImpl _customers;public Set?extends Customer g

27、etCustomers()return _customers;通配符和協(xié)變返回通配符的另一種常見用法是和協(xié)變返回一起使用。與賦值相同的規(guī)則可以應(yīng)用到協(xié)變返回上。如果希望在重寫的方法中返回一個更具體的泛型類型,聲明的方法必須使用通配符:public interface NumberGeneratorpublic List?extends Number generate();public class FibonacciGenerator extends NumberGeneratorpublic List Integer generate().如果要使用數(shù)組,接口可以返回Number,而實現(xiàn)可以返

28、回Integer。下限我們所談的主要是關(guān)于上限通配符的。還有一個下限通配符。List?super Number是一個確切元素類型未知的列表,但是可能是Mnumber,或者Number的超類型。所以它可能是一個List Number或一個List Object。下限通配符遠(yuǎn)沒有上限通配符那樣常見,但是當(dāng)需要它們的時候,它們就是必需的。下限與上限List?extends Number readList=new ArrayList Integer();Number n=readList.get(0);List?super Number writeList=new ArrayList Object()

29、;writeList.add(new Integer(5);第一個是可以從中讀數(shù)的列表。第二個是可以向其寫數(shù)的列表。無界通配符最后,List?列表的內(nèi)容可以是任何類型,而且它與List?extends Object幾乎相同??梢噪S時讀取Object,但是不能向列表中寫入內(nèi)容。公共API中的通配符總之,正如前面所說,通配符在向調(diào)用程序隱藏實現(xiàn)細(xì)節(jié)方面是非常重要的,但即使下限通配符看起來是提供只讀訪問,由于remove(int position)之類的非泛型方法,它們也并非如此。如果您想要一個真正不變的集合,可以使用java.util.Collection上的方法,比如unmodifiableLi

30、st()。編寫API的時候要記得通配符。通常,在傳遞泛型類型時,應(yīng)該嘗試使用通配符。它使更多的調(diào)用程序可以訪問API。通過接收List?extends Number而不是List Number,下面的方法可以由許多不同類型的列表調(diào)用:void removeNegatives(List?extends Number list);構(gòu)造泛型類型現(xiàn)在我們將討論構(gòu)造自己的泛型類型。我們將展示一些例子,其中通過使用泛型可以提高類型安全性,我們還將討論一些實現(xiàn)泛型類型時的常見問題。集合風(fēng)格(Collection-like)的函數(shù)第一個泛型類的例子是一個集合風(fēng)格的例子。Pair有兩個類型參數(shù),而且字段是類型的

31、實例:public final class Pair A,Bpublic final Afirst;public final Bsecond;public Pair(A first,B second)this.first=first;this.second=second;這使從方法返回兩個項而無需為每個兩種類型的組合編寫專用的類成為可能。另一種方法是返回Object,而這樣是類型不安全或者不整潔的。在下面的用法中,我們從方法返回一個File和一個Boolean。方法的客戶端可以直接使用字段而無需類型強(qiáng)制轉(zhuǎn)換:public Pair get(String path)/create status

32、return new Pair ();Pair result=get(.);boolean writeable=result.second;集合之外在下面這個例子中,泛型被用于附加的編譯時安全性。通過把DBFactory類參數(shù)化為所創(chuàng)建的Peer類型,您實際上是在強(qiáng)制Factory子類返回一個Peer的特定子類型:public abstract class DBFactory Textends DBPeerprotected abstract TcreateEmptyPeer();public List Tget(String constraint)List Tpeers=new ArrayList T()

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論