久久r热视频,国产午夜精品一区二区三区视频,亚洲精品自拍偷拍,欧美日韩精品二区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

體驗(yàn) JAVA 5 的新增語(yǔ)言特性

瀏覽:4日期:2024-06-16 11:20:37
內(nèi)容: Java 5.0發(fā)布了,許多人都將開(kāi)始使用這個(gè)JDK版本的一些新增特性。從增強(qiáng)的for循環(huán)到諸如泛型(generic)之類(lèi)更復(fù)雜的特性,都將很快出現(xiàn)在您所編寫(xiě)的代碼中。我們剛剛完成了一個(gè)基于Java 5.0的大型任務(wù),而本文就是要介紹我們使用這些新特性的體驗(yàn)。本文不是一篇入門(mén)性的文章,而是對(duì)這些特性以及它們所產(chǎn)生的影響的深入介紹,同時(shí)還給出了一些在項(xiàng)目中更有效地使用這些特性的技巧。 簡(jiǎn)介在JDK 1.5的beta階段,我們?yōu)锽EA的Java IDE開(kāi)發(fā)了一個(gè)Java 5編譯器。因?yàn)槲覀儗?shí)現(xiàn)了許多新特性,所以人們開(kāi)始以新的方式利用它們;有些用法很聰明,而有些用法明顯應(yīng)該被列入禁用清單。編譯器本身使用了新的語(yǔ)言特性,所以我們也獲得了使用這些特性維護(hù)代碼的直接體驗(yàn)。本文將介紹其中的許多特性和使用它們的體驗(yàn)。 我們假定您已經(jīng)熟悉了這些新特性,所以不再全面介紹每個(gè)特性,而是談?wù)撘恍┯腥さ摹⒌芸赡懿惶黠@的內(nèi)容和用法。這些技巧出自我們的實(shí)際體驗(yàn),并大致按照語(yǔ)言特性進(jìn)行了分類(lèi)。 我們將從最簡(jiǎn)單的特性開(kāi)始,逐步過(guò)渡到高級(jí)特性。泛型所包含的內(nèi)容特別豐富,因此占了本文一半的篇幅。增強(qiáng)的for循環(huán)為了迭代集合和數(shù)組,增強(qiáng)的for循環(huán)提供了一個(gè)簡(jiǎn)單、兼容的語(yǔ)法。有兩點(diǎn)值得一提: Init表達(dá)式在循環(huán)中,初始化表達(dá)式只計(jì)算一次。這意味著您通常可以移除一個(gè)變量聲明。在這個(gè)例子中,我們必須創(chuàng)建一個(gè)整型數(shù)組來(lái)保存computeNumbers()的結(jié)果,以防止每一次循環(huán)都重新計(jì)算該方法。您可以看到,下面的代碼要比上面的代碼整潔一些,并且沒(méi)有泄露變量numbers: 未增強(qiáng)的For:int sum = 0;Integer[] numbers = computeNumbers();for (int i=0; i < numbers.length ; i++) sum += numbers[i];增強(qiáng)后的For: int sum = 0;for ( int number: computeNumbers() ) sum += number;局限性有時(shí)需要在迭代期間訪(fǎng)問(wèn)迭代器或下標(biāo),看起來(lái)增強(qiáng)的for循環(huán)應(yīng)該允許該操作,但事實(shí)上不是這樣,請(qǐng)看下面的例子: for (int i=0; i < numbers.length ; i++) { if (i != 0) System.out.print(','); System.out.print(numbers[i]);}我們希望將數(shù)組中的值打印為一個(gè)用逗號(hào)分隔的清單。我們需要知道目前是否是第一項(xiàng),以便確定是否應(yīng)該打印逗號(hào)。使用增強(qiáng)的for循環(huán)是無(wú)法獲知這種信息的。我們需要自己保留一個(gè)下標(biāo)或一個(gè)布爾值來(lái)指示是否經(jīng)過(guò)了第一項(xiàng)。 這是另一個(gè)例子: for (Iterator it = n.iterator() ; it.hasNext() ; ) if (it.next() < 0) it.remove();在此例中,我們想從整數(shù)集合中刪除負(fù)數(shù)項(xiàng)。為此,需要對(duì)迭代器調(diào)用一個(gè)方法,但是當(dāng)使用增強(qiáng)的for 循環(huán)時(shí),迭代器對(duì)我們來(lái)說(shuō)是看不到的。因此,我們只能使用Java 5之前版本的迭代方法。 順便說(shuō)一下,這里需要注意的是,由于Iterator是泛型,所以其聲明是Iterator。許多人都忘記了這一點(diǎn)而使用了Iterator的原始格式。 注釋注釋處理是一個(gè)很大的話(huà)題。因?yàn)楸疚闹魂P(guān)注核心的語(yǔ)言特性,所以我們不打算涵蓋它所有的可能形式和陷阱。我們將討論內(nèi)置的注釋?zhuān)⊿uppressWarnings,Deprecated和Override)以及一般注釋處理的局限性。 Suppress Warnings該注釋關(guān)閉了類(lèi)或方法級(jí)別的編譯器警告。有時(shí)候您比編譯器更清楚地知道,代碼必須使用一個(gè)被否決的方法或執(zhí)行一些無(wú)法靜態(tài)確定是否類(lèi)型安全的動(dòng)作,而使用:@SuppressWarnings('deprecation')public static void selfDestruct() { Thread.currentThread().stop();}這可能是內(nèi)置注釋最有用的地方。遺憾的是,1.5.0_04的javac不支持它。但是1.6支持它,并且Sun正在努力將其向后移植到1.5中。 Eclipse 3.1中支持該注釋?zhuān)渌鸌DE也可能支持它。這允許您把代碼徹底地從警告中解脫出來(lái)。如果在編譯時(shí)出現(xiàn)警告,可以確定是您剛剛把它添加進(jìn)來(lái)——以幫助查看那些可能不安全的代碼。隨著泛型的添加,它使用起來(lái)將更趁手。 Deprecated遺憾的是,Deprecated沒(méi)那么有用。它本來(lái)旨在替換@deprecated javadoc標(biāo)簽,但是由于它不包含任何字段,所以也就沒(méi)有方法來(lái)建議deprecated類(lèi)或方法的用戶(hù)應(yīng)該使用什么做為替代品。大多數(shù)用法都同時(shí)需要javadoc標(biāo)簽和這個(gè)注釋。 Override Override表示,它所注釋的方法應(yīng)該重寫(xiě)超類(lèi)中具有相同簽名的方法: @Overridepublic int hashCode() { ...}看上面的例子,如果沒(méi)有在hashCode中將“C大寫(xiě),在編譯時(shí)不會(huì)出現(xiàn)錯(cuò)誤,但是在運(yùn)行時(shí)將無(wú)法像期望的那樣調(diào)用該方法。通過(guò)添加Override標(biāo)簽,編譯器會(huì)提示它是否真正地執(zhí)行了重寫(xiě)。 在超類(lèi)發(fā)生改變的情況中,這也很有幫助。如果向該方法中添加一個(gè)新參數(shù),而且方法本身也被重命名了,那么子類(lèi)將突然不能編譯,因?yàn)樗辉僦貙?xiě)超類(lèi)的任何東西。 其它注釋注釋在其他場(chǎng)景中非常有用。當(dāng)不是直接修改行為而是增強(qiáng)行為時(shí),特別是在添加樣板代碼的情況下,注釋在諸如EJB和Web services這樣的框架中運(yùn)行得非常好。 注釋不能用做預(yù)處理器。Sun的設(shè)計(jì)特別預(yù)防了完全因?yàn)樽⑨尪薷念?lèi)的字節(jié)碼。這樣可以正確地理解該語(yǔ)言的成果,而且IDE之類(lèi)的工具也可以執(zhí)行深入的代碼分析和重構(gòu)之類(lèi)的功能。 注釋不是銀彈。第一次遇到的時(shí)候,人們?cè)噲D嘗試各種技巧。請(qǐng)看下面這個(gè)從別人那里獲得的建議: public class Foo { @Property private int bar; }其思想是為私有字段bar自動(dòng)創(chuàng)建getter和setter方法。遺憾的是,這個(gè)想法有兩個(gè)失敗之處:1)它不能運(yùn)行,2)它使代碼難以閱讀和處理。 它是無(wú)法實(shí)現(xiàn)的,因?yàn)榍懊嬉呀?jīng)提到了,Sun特別阻止了對(duì)出現(xiàn)注釋的類(lèi)進(jìn)行修改。 即使是可能的,它也不是一個(gè)好主意,因?yàn)樗勾a可讀性差。第一次看到這段代碼的人會(huì)不知道該注釋創(chuàng)建了方法。此外,如果將來(lái)您需要在這些方法內(nèi)部執(zhí)行一些操作,注釋也是沒(méi)用的。 總之,不要試圖用注釋去做那些常規(guī)代碼可以完成的事情。 枚舉 enum非常像public static final int聲明,后者作為枚舉值已經(jīng)使用了很多年。對(duì)int所做的最大也是最明顯的改進(jìn)是類(lèi)型安全——您不能錯(cuò)誤地用枚舉的一種類(lèi)型代替另一種類(lèi)型,這一點(diǎn)和int不同,所有的int對(duì)編譯器來(lái)說(shuō)都是一樣的。除去極少數(shù)例外的情況,通常都應(yīng)該用enum實(shí)例替換全部的枚舉風(fēng)格的int結(jié)構(gòu)。 枚舉提供了一些附加的特性。EnumMap和EnumSet這兩個(gè)實(shí)用類(lèi)是專(zhuān)門(mén)為枚舉優(yōu)化的標(biāo)準(zhǔn)集合實(shí)現(xiàn)。如果知道集合只包含枚舉類(lèi)型,那么應(yīng)該使用這些專(zhuān)門(mén)的集合來(lái)代替HashMap或HashSet。 大部分情況下,可以使用enum對(duì)代碼中的所有public static final int做插入替換。它們是可比的,并且可以靜態(tài)導(dǎo)入,所以對(duì)它們的引用看起來(lái)是等同的,即使是對(duì)于內(nèi)部類(lèi)(或內(nèi)部枚舉類(lèi)型)。注意,比較枚舉類(lèi)型的時(shí)候,聲明它們的指令表明了它們的順序值。 “隱藏的靜態(tài)方法 兩個(gè)靜態(tài)方法出現(xiàn)在所有枚舉類(lèi)型聲明中。因?yàn)樗鼈兪敲杜e子類(lèi)上的靜態(tài)方法,而不是Enum本身的方法,所以它們?cè)趈ava.lang.Enum的javadoc中沒(méi)有出現(xiàn)。 第一個(gè)是values(),返回一個(gè)枚舉類(lèi)型所有可能值的數(shù)組。 第二個(gè)是valueOf(),為提供的字符串返回一個(gè)枚舉類(lèi)型,該枚舉類(lèi)型必須精確地匹配源代碼聲明。 方法關(guān)于枚舉類(lèi)型,我們最喜歡的一個(gè)方面是它可以有方法。過(guò)去您可能需要編寫(xiě)一些代碼,對(duì)public static final int進(jìn)行轉(zhuǎn)換,把它從數(shù)據(jù)庫(kù)類(lèi)型轉(zhuǎn)換為JDBC URL。而現(xiàn)在則可以讓枚舉類(lèi)型本身帶一個(gè)整理代碼的方法。下面就是一個(gè)例子,包括DatabaseType枚舉類(lèi)型的抽象方法以及每個(gè)枚舉實(shí)例中提供的實(shí)現(xiàn): public enum DatabaseType { ORACLE { public String getJdbcUrl() {...} }, MYSQL { public String getJdbcUrl() {...} }; public abstract String getJdbcUrl(); }現(xiàn)在枚舉類(lèi)型可以直接提供它的實(shí)用方法。例如:DatabaseType dbType = ...;String jdbcURL = dbType.getJdbcUrl();要獲取URL,必須預(yù)先知道該實(shí)用方法在哪里。 可變參數(shù)(Vararg)正確地使用可變參數(shù)確實(shí)可以清理一些垃圾代碼。典型的例子是一個(gè)帶有可變的String參數(shù)個(gè)數(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í),比較有趣的是,如果用新的可變參數(shù)替換前四個(gè)例子,將是兼容的: Log.log(String code, String... args)所有的可變參數(shù)都是源兼容的——那就是說(shuō),如果重新編譯log()方法的所有調(diào)用程序,可以直接替換全部的四個(gè)方法。然而,如果需要向后的二進(jìn)制兼容性,那么就需要舍去前三個(gè)方法。只有最后那個(gè)帶一個(gè)字符串?dāng)?shù)組參數(shù)的方法等效于可變參數(shù)版本,因此可以被可變參數(shù)版本替換。 類(lèi)型強(qiáng)制轉(zhuǎn)換 如果希望調(diào)用程序了解應(yīng)該使用哪種類(lèi)型的參數(shù),那么應(yīng)該避免用可變參數(shù)進(jìn)行類(lèi)型強(qiáng)制轉(zhuǎn)換。看下面這個(gè)例子,第一項(xiàng)希望是String,第二項(xiàng)希望是Exception: Log.log(Object... objects) { String message = (String)objects[0]; if (objects.length> 1) { Exception e = (Exception)objects[1]; // Do something with the exception } }方法簽名應(yīng)該如下所示,相應(yīng)的可變參數(shù)分別使用String和Exception聲明: Log.log(String message, Exception e, Object... objects) {...}不要使用可變參數(shù)破壞類(lèi)型系統(tǒng)。需要強(qiáng)類(lèi)型化時(shí)才可以使用它。對(duì)于這個(gè)規(guī)則,PrintStream.printf()是一個(gè)有趣的例外:它提供類(lèi)型信息作為自己的第一個(gè)參數(shù),以便稍后可以接受那些類(lèi)型。 協(xié)變返回 協(xié)變返回的基本用法是用于在已知一個(gè)實(shí)現(xiàn)的返回類(lèi)型比API更具體的時(shí)候避免進(jìn)行類(lèi)型強(qiáng)制轉(zhuǎn)換。在下面這個(gè)例子中,有一個(gè)返回Animal對(duì)象的Zoo接口。我們的實(shí)現(xiàn)返回一個(gè)AnimalImpl對(duì)象,但是在JDK 1.5之前,要返回一個(gè)Animal對(duì)象就必須聲明。: public interface Zoo { public Animal getAnimal(); } public class ZooImpl implements Zoo { public Animal getAnimal(){ return new AnimalImpl(); } }協(xié)變返回的使用替換了三個(gè)反模式: 直接字段訪(fǎng)問(wèn)。為了規(guī)避API限制,一些實(shí)現(xiàn)把子類(lèi)直接暴露為字段: ZooImpl._animal另一種形式是,在知道實(shí)現(xiàn)的實(shí)際上是特定的子類(lèi)的情況下,在調(diào)用程序中執(zhí)行向下轉(zhuǎn)換: ((AnimalImpl)ZooImpl.getAnimal()).implMethod();我看到的最后一種形式是一個(gè)具體的方法,該方法用來(lái)避免由一個(gè)完全不同的簽名所引發(fā)的問(wèn)題: ZooImpl._getAnimal();這三種模式都有它們的問(wèn)題和局限性。要么是不夠整潔,要么就是暴露了不必要的實(shí)現(xiàn)細(xì)節(jié)。 協(xié)變 協(xié)變返回模式就比較整潔、安全并且易于維護(hù),它也不需要類(lèi)型強(qiáng)制轉(zhuǎn)換或特定的方法或字段: public AnimalImpl getAnimal(){return new AnimalImpl();}使用結(jié)果: ZooImpl.getAnimal().implMethod();使用泛型我們將從兩個(gè)角度來(lái)了解泛型:使用泛型和構(gòu)造泛型。我們不討論List、Set和Map的顯而易見(jiàn)的用法。知道泛型集合是強(qiáng)大的并且應(yīng)該經(jīng)常使用就足夠了。 我們將討論泛型方法的使用以及編譯器推斷類(lèi)型的方法。通常這些都不會(huì)出問(wèn)題,但是當(dāng)出問(wèn)題時(shí),錯(cuò)誤信息會(huì)非常令人費(fèi)解,所以需要了解如何修復(fù)這些問(wèn)題。 泛型方法除了泛型類(lèi)型,Java 5還引入了泛型方法。在這個(gè)來(lái)自java.util.Collections的例子中,構(gòu)造了一個(gè)單元素列表。新的List的元素類(lèi)型是根據(jù)傳入方法的對(duì)象的類(lèi)型來(lái)推斷的: static List Collections.singletonList(T o)示例用法:public List getListOfOne() { return Collections.singletonList(1);}在示例用法中,我們傳入了一個(gè)int。所以方法的返回類(lèi)型就是List。編譯器把T推斷為Integer。這和泛型類(lèi)型是不同的,因?yàn)槟ǔ2恍枰@式地指定類(lèi)型參數(shù)。 這也顯示了自動(dòng)裝箱和泛型的相互作用。類(lèi)型參數(shù)必須是引用類(lèi)型:這就是為什么我們得到的是List而不是List。 不帶參數(shù)的泛型方法emptyList()方法與泛型一起引入,作為java.util.Collections中EMPTY_LIST字段的類(lèi)型安全置換: static List Collections.emptyList()示例用法: public List getNoIntegers() { return Collections.emptyList();}與先前的例子不同,這個(gè)方法沒(méi)有參數(shù),那么編譯器如何推斷T的類(lèi)型呢?基本上,它將嘗試使用一次參數(shù)。如果沒(méi)有起作用,它再次嘗試使用返回或賦值類(lèi)型。在本例中,返回的是List,所以T被推斷為Integer。 如果在返回語(yǔ)句或賦值語(yǔ)句之外的位置調(diào)用泛型方法會(huì)怎么樣呢?那么編譯器將無(wú)法執(zhí)行類(lèi)型推斷的第二次傳送。在下面這個(gè)例子中,emptyList()是從條件運(yùn)算符內(nèi)部調(diào)用的: public List getNoIntegers() { return x ? Collections.emptyList() : null;}因?yàn)榫幾g器看不到返回上下文,也不能推斷T,所以它放棄并采用Object。您將看到一個(gè)錯(cuò)誤消息,比如:“無(wú)法將List轉(zhuǎn)換為L(zhǎng)ist。 為了修復(fù)這個(gè)錯(cuò)誤,應(yīng)顯式地向方法調(diào)用傳遞類(lèi)型參數(shù)。這樣,編譯器就不會(huì)試圖推斷類(lèi)型參數(shù),就可以獲得正確的結(jié)果: return x ? Collections.emptyList() : null;這種情況經(jīng)常發(fā)生的另一個(gè)地方是在方法調(diào)用中。如果一個(gè)方法帶一個(gè)List參數(shù),并且需要為那個(gè)參數(shù)調(diào)用這個(gè)傳遞的emptyList(),那么也需要使用這個(gè)語(yǔ)法。 集合之外這里有三個(gè)泛型類(lèi)型的例子,它們不是集合,而是以一種新穎的方式使用泛型。這三個(gè)例子都來(lái)自標(biāo)準(zhǔn)的Java庫(kù): ClassClass在類(lèi)的類(lèi)型上被參數(shù)化了。這就使無(wú)需類(lèi)型強(qiáng)制轉(zhuǎn)換而構(gòu)造一個(gè)newInstance成為可能。 ComparableComparable被實(shí)際的比較類(lèi)型參數(shù)化。這就在compareTo()調(diào)用時(shí)提供了更強(qiáng)的類(lèi)型化。例如,String實(shí)現(xiàn)Comparable。對(duì)除String之外的任何東西調(diào)用compareTo(),都會(huì)在編譯時(shí)失敗。 EnumEnum被枚舉類(lèi)型參數(shù)化。一個(gè)名為Color的枚舉類(lèi)型將擴(kuò)展Enum。getDeclaringClass()方法返回枚舉類(lèi)型的類(lèi)對(duì)象,在這個(gè)例子中就是一個(gè)Color對(duì)象。它與getClass()不同,后者可能返回一個(gè)無(wú)名類(lèi)。 通配符泛型最復(fù)雜的部分是對(duì)通配符的理解。我們將討論三種類(lèi)型的通配符以及它們的用途。 首先讓我們了解一下數(shù)組是如何工作的。可以從一個(gè)Integer[]為一個(gè)Number[]賦值。如果嘗試把一個(gè)Float寫(xiě)到Number[]中,那么可以編譯,但在運(yùn)行時(shí)會(huì)失敗,出現(xiàn)一個(gè)ArrayStoreException: Integer[] ia = new Integer[5];Number[] na = ia;na[0] = 0.5; // compiles, but fails at runtime如果試圖把該例直接轉(zhuǎn)換成泛型,那么會(huì)在編譯時(shí)失敗,因?yàn)橘x值是不被允許的:List iList = new ArrayList();List nList = iList; // not allowednList.add(0.5);如果使用泛型,只要代碼在編譯時(shí)沒(méi)有出現(xiàn)警告,就不會(huì)遇到運(yùn)行時(shí)ClassCastException。 上限通配符我們想要的是一個(gè)確切元素類(lèi)型未知的列表,這一點(diǎn)與數(shù)組是不同的。 List是一個(gè)列表,其元素類(lèi)型是具體類(lèi)型Number。 List<? extends Number>是一個(gè)確切元素類(lèi)型未知的列表。它是Number或其子類(lèi)型。 上限如果我們更新初始的例子,并賦值給List<? extends Number>,那么現(xiàn)在賦值就會(huì)成功了: List iList = new ArrayList();List<? extends Number> nList = iList;Number n = nList.get(0);nList.add(0.5); // Not allowed我們可以從列表中得到Number,因?yàn)闊o(wú)論列表的確切元素類(lèi)型是什么(Float、Integer或Number),我們都可以把它賦值給Number。 我們?nèi)匀徊荒馨迅↑c(diǎn)類(lèi)型插入列表中。這會(huì)在編譯時(shí)失敗,因?yàn)槲覀儾荒茏C明這是安全的。如果我們想要向列表中添加浮點(diǎn)類(lèi)型,它將破壞iList的初始類(lèi)型安全——它只存儲(chǔ)Integer。 通配符給了我們比數(shù)組更多的表達(dá)能力。 為什么使用通配符在下面這個(gè)例子中,通配符用于向API的用戶(hù)隱藏類(lèi)型信息。在內(nèi)部,Set被存儲(chǔ)為CustomerImpl。而API的用戶(hù)只知道他們正在獲取一個(gè)Set,從中可以讀取Customer。 此處通配符是必需的,因?yàn)闊o(wú)法從Set向Set賦值: public class CustomerFactory { private Set _customers; public Set<? extends Customer> getCustomers() { return _customers; }}通配符和協(xié)變返回通配符的另一種常見(jiàn)用法是和協(xié)變返回一起使用。與賦值相同的規(guī)則可以應(yīng)用到協(xié)變返回上。如果希望在重寫(xiě)的方法中返回一個(gè)更具體的泛型類(lèi)型,聲明的方法必須使用通配符: public interface NumberGenerator { public List<? extends Number> generate();}public class FibonacciGenerator extends NumberGenerator { public List generate() { ... }}如果要使用數(shù)組,接口可以返回Number[],而實(shí)現(xiàn)可以返回Integer[]。 下限 我們所談的主要是關(guān)于上限通配符的。還有一個(gè)下限通配符。List<? super Number>是一個(gè)確切“元素類(lèi)型未知的列表,但是可能是Mnumber,或者Number的超類(lèi)型。所以它可能是一個(gè)List或一個(gè)List。 下限通配符遠(yuǎn)沒(méi)有上限通配符那樣常見(jiàn),但是當(dāng)需要它們的時(shí)候,它們就是必需的。 下限與上限List<? extends Number> readList = new ArrayList();Number n = readList.get(0);List<? super Number> writeList = new ArrayList();writeList.add(new Integer(5));第一個(gè)是可以從中讀數(shù)的列表。 第二個(gè)是可以向其寫(xiě)數(shù)的列表。 無(wú)界通配符最后,List<?>列表的內(nèi)容可以是任何類(lèi)型,而且它與List<? extends Object>幾乎相同。可以隨時(shí)讀取Object,但是不能向列表中寫(xiě)入內(nèi)容。 公共API中的通配符 總之,正如前面所說(shuō),通配符在向調(diào)用程序隱藏實(shí)現(xiàn)細(xì)節(jié)方面是非常重要的,但即使下限通配符看起來(lái)是提供只讀訪(fǎng)問(wèn),由于remove(int position)之類(lèi)的非泛型方法,它們也并非如此。如果您想要一個(gè)真正不變的集合,可以使用java.util.Collection上的方法,比如unmodifiableList()。 編寫(xiě)API的時(shí)候要記得通配符。通常,在傳遞泛型類(lèi)型時(shí),應(yīng)該嘗試使用通配符。它使更多的調(diào)用程序可以訪(fǎng)問(wèn)API。 通過(guò)接收List<? extends Number>而不是List,下面的方法可以由許多不同類(lèi)型的列表調(diào)用: void removeNegatives(List<? extends Number> list);構(gòu)造泛型類(lèi)型現(xiàn)在我們將討論構(gòu)造自己的泛型類(lèi)型。我們將展示一些例子,其中通過(guò)使用泛型可以提高類(lèi)型安全性,我們還將討論一些實(shí)現(xiàn)泛型類(lèi)型時(shí)的常見(jiàn)問(wèn)題。集合風(fēng)格(Collection-like)的函數(shù)第一個(gè)泛型類(lèi)的例子是一個(gè)集合風(fēng)格的例子。Pair有兩個(gè)類(lèi)型參數(shù),而且字段是類(lèi)型的實(shí)例: public final class Pair { public final A first; public final B second; public Pair(A first, B second) { this.first = first; this.second = second; }}這使從方法返回兩個(gè)項(xiàng)而無(wú)需為每個(gè)兩種類(lèi)型的組合編寫(xiě)專(zhuān)用的類(lèi)成為可能。另一種方法是返回Object[],而這樣是類(lèi)型不安全或者不整潔的。 在下面的用法中,我們從方法返回一個(gè)File和一個(gè)Boolean。方法的客戶(hù)端可以直接使用字段而無(wú)需類(lèi)型強(qiáng)制轉(zhuǎn)換: public Pair getFileAndWriteStatus(String path){ // create file and status return new Pair(file, status);}Pair result = getFileAndWriteStatus('...');File f = result.first;boolean writeable = result.second;集合之外 在下面這個(gè)例子中,泛型被用于附加的編譯時(shí)安全性。通過(guò)把DBFactory類(lèi)參數(shù)化為所創(chuàng)建的Peer類(lèi)型,您實(shí)際上是在強(qiáng)制Factory子類(lèi)返回一個(gè)Peer的特定子類(lèi)型: public abstract class DBFactory { protected abstract T createEmptyPeer(); public List get(String constraint) { List peers = new ArrayList(); // database magic return peers; }}通過(guò)實(shí)現(xiàn)DBFactory,CustomerFactory必須從createEmptyPeer()返回一個(gè)Customer:public class CustomerFactory extends DBFactory{ public Customer createEmptyPeer() { return new Customer(); }}泛型方法不管想要對(duì)參數(shù)之間還是參數(shù)與返回類(lèi)型之間的泛型類(lèi)型施加約束,都可以使用泛型方法: 例如,如果編寫(xiě)的反轉(zhuǎn)函數(shù)是在位置上反轉(zhuǎn),那么可能不需要泛型方法。然而,如果希望反轉(zhuǎn)返回一個(gè)新的List,那么可能會(huì)希望新List的元素類(lèi)型與傳入的List的類(lèi)型相同。在這種情況下,就需要一個(gè)泛型方法: List reverse(List list) 具體化當(dāng)實(shí)現(xiàn)一個(gè)泛型類(lèi)時(shí),您可能想要構(gòu)造一個(gè)數(shù)組T[]。因?yàn)榉盒褪峭ㄟ^(guò)擦除(erasure)實(shí)現(xiàn)的,所以這是不允許的。 您可以嘗試把Object[]強(qiáng)制轉(zhuǎn)換為T(mén)[]。但這是不安全的。 具體化解決方案按照泛型教程的慣例,解決方案使用的是“類(lèi)型令牌,通過(guò)向構(gòu)造函數(shù)添加一個(gè)Class參數(shù),可以強(qiáng)制客戶(hù)端為類(lèi)的類(lèi)型參數(shù)提供正確的類(lèi)對(duì)象: public class ArrayExample { private Class clazz; public ArrayExample(Class clazz) { this.clazz = clazz; } public T[] getArray(int size) { return (T[])Array.newInstance(clazz, size); }}為了構(gòu)造ArrayExample,客戶(hù)端必須把String.class傳遞給構(gòu)造函數(shù),因?yàn)镾tring.class的類(lèi)型是Class。 擁有類(lèi)對(duì)象使構(gòu)造一個(gè)具有正確元素類(lèi)型的數(shù)組成為可能。 結(jié)束語(yǔ)總而言之,新的語(yǔ)言特性有助于從根本上改變Java。通過(guò)了解在什么場(chǎng)景下使用以及如何使用這些新特性,您將會(huì)編寫(xiě)出更好的代碼。補(bǔ)充閱讀 1.Enhancements in JDK 5——JDK 5中新特性的官方列表 2.Generics Tutorial (PDF)——Gilad Bracha的泛型教程 Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd Java 5.0發(fā)布了,許多人都將開(kāi)始使用這個(gè)JDK版本的一些新增特性。從增強(qiáng)的for循環(huán)到諸如泛型(generic)之類(lèi)更復(fù)雜的特性,都將很快出現(xiàn)在您所編寫(xiě)的代碼中。我們剛
標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 潼关县| 林甸县| 石棉县| 荔波县| 平和县| 巍山| 阿克陶县| 曲阜市| 麦盖提县| 县级市| 大冶市| 罗源县| 栾川县| 芜湖县| 吕梁市| 周至县| 韶关市| 迁西县| 玉山县| 庄浪县| 荥阳市| 怀来县| 嘉祥县| 肃宁县| 漳平市| 调兵山市| 连平县| 施甸县| 保亭| 柯坪县| 灯塔市| 秭归县| 壶关县| 淮安市| 海伦市| 庆元县| 津南区| 内丘县| 仲巴县| 开原市| 公安县|