<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    空間站

    北極心空

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks
    說明:以下內容來自http://www.javaeye.com/topic/24794?page=1
    Julysea 網(wǎng)友

    做些說明吧:轉網(wǎng)頁的東西,改起來稍覺得的麻煩,就可能滯后。不過pdf文件會不定時的及時更新


    4.1. Generic Types
    Generic types and methods are the defining new feature of Java 5.0. A generic type is defined using one or more type variables and has one or more methods that use a type variable as a placeholder for an argument or return type. For example, the type java.util.List<E> is a generic type: a list that holds elements of some type represented by the placeholder E. This type has a method named add(), declared to take an argument of type E, and a method named get(), declared to return a value of type E.

    4.1. 泛型

    泛類型和泛型方法是Java5.0中的新特性。一種泛類型用一個或多個泛型變量定義,可以有一個或多個,泛型變量做參數(shù)占位符或做返回值的方法。例如,類型 java.util.List<E> 是一種泛類型:一個 list ,它的元素類型是E 這個占位符表示的類型。這個類型有一個叫 add() 的方法,有一個參數(shù)類型為 E ,有一個名叫 get() 的方法,返回一個類型為 E 的值。

    In order to use a generic type like this, you specify actual types for the type variable (or variables), producing a parameterized type such as List<String>.[1] The reason to specify this extra type information is that the compiler can provide much stronger compile-time type checking for you, increasing the type safety of your programs. This type checking prevents you from adding a String[], for example, to a List that is intended to hold only String objects. Also, the additional type information enables the compiler to do some casting for you. The compiler knows that the get( ) method of a List<String> (for example) returns a String object: you are no longer required to cast a return value of type Object to a String.

    為了可以象往常一樣使用泛類型,你需要為泛型變量(或是變量)指定一個實際的類型,產(chǎn)生一個參數(shù)化類型,就象 List<String> 。這樣做的原因是,為編譯器提供一個特定的類型信息,讓它可以在編譯期為你做類型檢查,這樣可以大大增加你程序的類型安全。例如,有一個 List 打算容納 String 類型的對象,這種類型安全檢查阻止你增加一個String[] 的元素。而且,這附加的類型信息使編譯器幫你做些造型的活兒。例如,編譯器知道 List<String> 的 get() 方法返回一個String類型對象,你不再需要把Object類型的返回值造型成一個String類型的對象。

    [1] Throughout this chapter, I've tried to consistently use the term " generic type" to mean a type that declares one or more type variables and the term "parameterized type" to mean a generic type that has had actual type arguments substituted for its type varaiables. In common usage, however, the distinction is not a sharp one and the terms are sometimes used interchangeably.

    [1] 整個這章,我們將統(tǒng)一使用這些術語。"泛類型":意味著一個類型,可以聲明一個或多個泛型變量。"參數(shù)化類型",意味著一個(運行期的)泛類型,表示它的泛型變量被實際類型做為參數(shù)值替換了。但在通常的應用中,兩個術語的差別不是太明顯,有時還可以替換。

    The collections classes of the java.util package have been made generic in Java 5.0, and you will probably use them frequently in your programs. Typesafe collections are the canonical use case for generic types. Even if you never define generic types of your own and never use generic types other than the collections classes in java.util, the benefits of typesafe collections are so significant that they justify the complexity of this major new language feature.

    在Java 5.0中,包java.util中的Collection類都已經(jīng)被泛化了,你可能會在程序中頻繁的用到它們。類型安全的Collection是應用泛類型的典范??赡苣氵€從沒有定義過自己的泛類型,也從沒用過Collection(在包 java.uitl中)之外的泛類型,但類型安全的Collection的好處是顯而易見的,它將證實這個新的,復雜的,主要且重要的語言特性。

    We begin by exploring the basic use of generics in typesafe collections, then delve into more complex details about the use of generic types. Next we cover type parameter wildcards and bounded wildcards. After describing how to use generic types, we explain how to write your own generic types and generic methods. Our coverage of generics concludes with a tour of important generic types in the core Java API. It explores these types and their use in depth in order to provide a deeper understanding of how generics work.

    我們將從探索類型安全的Collection的基本泛化用法開始,然后深入泛類型用法更為復雜的細節(jié)。接下來,我們將覆蓋泛型參數(shù)通配符和邊界通配符。再說明怎么用泛類型,我們將闡述怎樣寫自己的泛類型和泛型方法。我們涉及的泛型知識包括了 Java API 中關于泛類型的主要部分。深入的探討了這些類型和他們的用法,為的是更深入的理解泛型是如何工作的。

    4.1.1. Typesafe Collections
    4.1.1.類型安全的Collection

    The java.util package includes the Java Collections Framework for working with sets and lists of objects and mappings from key objects to value objects. Collections are covered in Chapter 5. Here, we discuss the fact that in Java 5.0 the collections classes use type parameters to identify the type of the objects in the collection. This is not the case in Java 1.4 and earlier. Without generics, the use of collections requires the programmer to remember the proper element type for each collection. When you create a collection in Java 1.4, you know what type of objects you intend to store in that collection, but the compiler cannot know this. You must be careful to add elements of the appropriate type. And when querying elements from a collection, you must write explicit casts to convert them from Object to their actual type. Consider the following Java 1.4 code:

    在包 java.util 中包含了 Java 的Collection框架(set、list--關于對象、map--關于關鍵字對象和值對象的對)。 Collection 將在第五章討論。這里我們只討論有關在 Java 5.0 的Collection類中,用泛型參數(shù)標識Collection對象類型的內容。這在 Java 1.4 或是更早的 Java 版本中,沒有這個用法。在沒有泛型應用Collection的時候,需要程序員正確記得每個Collection的每個元素的類型。當我們建立一個 Java 1.4 的Collection時,你知道打算把什么樣的類型對象放入這個Collection中,但是編譯器不知道這些。你增加元素時必須小心正確性。并且當獲取一個Collection的元素時,你必須顯示的造型對象Object 到它們實際的類型。思考在 Java 1.4 中的如下代碼:
    Java代碼 復制代碼
    1. public static void main(String[] args) {   
    2.     // This list is intended to hold only strings.   
    3.       // 這個list僅容納字符串對象。   
    4.     // The compiler doesn't know that so we have to remember ourselves.   
    5.     // 編譯器不知道這些,我們必須自己記住。   
    6.     List wordlist = new ArrayList();     
    7.     
    8.     // Oops! We added a String[] instead of a String.   
    9.     // 哎喲! 我們增加了個String[]元素,而不是String類型的。   
    10.     // The compiler doesn't know that this is an error.   
    11.     // 編譯器是不知道那個錯誤的   
    12.     wordlist.add(args);   
    13.     
    14.     // Since List can hold arbitrary objects, the get() method returns   
    15. // Object.  Since the list is intended to hold strings, we cast the   
    16. // return value to String but get a ClassCastException because of   
    17. // the error above.   
    18. // 因為 List 能容納任意的對象,方法僅返回Object的對象。因為這個 list 打算   
    19. // 存儲字符串的,我們把返回值轉換成字符串,但卻因為上面的錯誤得到了一個   
    20. // ClassCastException的異常。   
    21.        
    22.     String word = (String)wordlist.get(0);   
    23. }  


    Generic types solve the type safety problem illustrated by this code. List and the other collection classes in java.util have been rewritten to be generic. As mentioned above, List has been redefined in terms of a type variable named E that represents the type of the elements of the list. The add( ) method is redefined to expect an argument of type E instead of Object and get( ) has been redefined to return E instead of Object.

    泛類型就是解決上面示例的安全性問題的。在包java.utiil中的List和其他的Collection類都應用泛型重寫過了。在上面說到的,List已被應用泛型變量 E (表示 list 中元素的類型) 重新定義過了, add() 方法被重定義成,要求傳遞一個類型為E而不是Object的參數(shù);get()方法被重定義成返回一個類型為E而不是 Object 的值。

    In Java 5.0, when we declare a List variable or create an instance of an ArrayList, we specify the actual type we want E to represent by placing the actual type in angle brackets following the name of the generic type. A List that holds strings is a List<String>, for example. Note that this is much like passing an argument to a method, except that we use types rather than values and angle brackets instead of parentheses.

    在 Java 5.0 ,當我們聲明一個List變量或是創(chuàng)建一個ArrayList的實例時,我們指定一個實際少泛型替換類型占位符E,這個實際類型被放到泛類型名后的尖括號內。例如,一個容納字符串類型的List就這樣寫List<String>。注意,這個很象一個有合法參數(shù)的方法,除了我們用類型替換了值,用尖括號替換了圓括號。

    The elements of the java.util collection classes must be objects; they cannot be used with primitive values. The introduction of generics does not change this. Generics do not work with primitives: we can't declare a Set<char>, or a List<int> for example. Note, however, that the autoboxing and autounboxing features of Java 5.0 make working with a Set<Character> or a List<Integer> just as easy as working directly with char and int values. (See Chapter 2 for details on autoboxing and autounboxing).

    包java.util中的類的元素必須是對象;它們不能用原生類型。引進泛型并不能改變這一點。泛型應用不是針對原生類型的。例如,我們不能聲明Set<char>或是List<int>。但是,注意了,由于Java 5.0自動裝箱和自動拆箱的新特性,我們可以應用Set<Character>或是List<Integer>,而直接使用char和int的值(參見第二章關于自動裝箱和自動拆箱的詳細講述)。

    In Java 5.0, the example above would be rewritten as follows:

    在Java 5.0,上面的例子可能被重寫成如下形式:
    Java代碼 復制代碼
    1. public static void main(String[] args) {   
    2.     // This list can only hold String objects   
    3. // 這個 list 僅能容納字符串對象   
    4.     List<String> wordlist = new ArrayList<String>();   
    5.     
    6.     // args is a String[], not String, so the compiler won't let us do this   
    7.       // args 是 String [] 類型的,不是String,因此編譯器不讓那么做。   
    8.     wordlist.add(args);  // Compilation error!  // 編譯錯誤!   
    9.     
    10.     // We can do this, though.     
    11. // Notice the use of the new for/in looping statement   
    12. // 然后,我們可以這么做   
    13.     // 注意這個新的for/in的用法   
    14.     for(String arg : args) wordlist.add(arg);   
    15.     
    16.     // No cast is required.  List<String>.get() returns a String.   
    17.       // 不需要造型轉換。 List<String>.get() 返回一個字符串。   
    18.     String word = wordlist.get(0);   
    19. }  


    Note that this code isn't much shorter than the nongeneric example it replaces. The cast, which uses the word String in parentheses, is replaced with the type parameter, which places the word String in angle brackets. The difference is that the type parameter has to be declared only once, but the list can be used any number of times without a cast. This would be more apparent in a longer example. But even in cases where the generic syntax is more verbose than the nongeneric syntax, it is still very much worth using generics because the extra type information allows the compiler to perform much stronger error checking on your code. Errors that would only be apparent at runtime can now be detected at compile time. Furthermore, the compilation error appears at the exact line where the type safety violation occurs. Without generics, a ClassCastException can be thrown far from the actual source of the error.

    可以看到這段代碼并不比非泛型的短多少。圓號形式的造型轉換被尖括號的泛型參數(shù)替代了。不同的是,泛型參數(shù)只聲明了一次,而list可以用很多次,且不用造型轉換。在比較長的代碼中這是顯而易見的。但是,泛型語法比非泛型語法要繁瑣很多,可是這是非常值得的,因為附加的類型信息允許編譯器對你的代碼執(zhí)行強類型錯誤檢查。這樣運行期的錯誤可以在編譯時就被找到。特別是,編譯期里違反類型安全錯誤可以精確到行。若無泛型,一個ClassCastException的異常將會在源代碼中很遠的位置拋出。

    Just as methods can have any number of arguments, classes can have more than one type variable. The java.util.Map interface is an example. A Map is a mapping from key objects to value objects. The Map interface declares one type variable to represent the type of the keys and one variable to represent the type of the values. As an example, suppose you want to map from String objects to Integer objects:

    正如方法可以很多的參數(shù)一樣,類可以有不止一種泛型變量。java.util.Map接口就是一個例子。一個Map是一個關鍵字對象和值對象的對。Map接口聲明了一個表示關鍵字對象類型的泛型變量和一個表示值對象類型的泛型變量。例如,我們假定你有一個關鍵字類型為String,值類型為Integer的map:
    Java代碼 復制代碼
    1. public static void main(String[] args) {   
    2.     // A map from strings to their position in the args[] array   
    3.       // 一個關鍵字為字符串類型,表示args[] 數(shù)組位置的map   
    4.     Map<String,Integer> map = new HashMap<String,Integer>();   
    5.     
    6.     // Note that we use autoboxing to wrap i in an Integer object.   
    7.       // 注意了,我們用自動裝箱把i放進Integer的對象中。   
    8.     for(int i=0; i < args.length; i++) map.put(args[i], i);     
    9.     
    10.     // Find the array index of a word.  Note no cast is required!   
    11.       // 查找數(shù)組中的一個單詞。注意,不需要造型!   
    12.     Integer position = map.get("hello");   
    13.     
    14.     // We can also rely on autounboxing to convert directly to an int,   
    15.     // but this throws a NullPointerException if the key does not exist    
    16.     // in the map   
    17.       // 但是這個關鍵字在 map 中不存在,會拋出一個NullPointerException異常   
    18.      // 我也可以直接依靠自動拆箱把對象轉化成int的值。   
    19.     
    20.     int pos = map.get("world");   
    21. }  


    A parameterized type like List<String> is itself a type and can be used as the value of a type parameter for some other type. You might see code like this:

    一個象List<String>的 參數(shù)化類型是它自己的一個類型,可以作為值用作其他類型的參數(shù)化類型。你可以看下面的代碼:
    Java代碼 復制代碼
    1. // Look at all those nested angle brackets!   
    2. // 注意看這些嵌套的尖括號!   
    3. Map<String, List<List<int[]>>> map = getWeirdMap();   
    4.     
    5. // The compiler knows all the types and we can write expressions   
    6. // 編譯器我們寫的表達式的所有類型   
    7. // like this without casting.  We might still get NullPointerException   
    8. // 象這種沒有造型轉換的。當然,我們仍然可能在運行時,得到 NullPointerException 異常   
    9. // or ArrayIndexOutOfBounds at runtime, of course.   
    10. // 或是 ArrayIndexOutOfBounds 異常   
    11. int value = map.get(key).get(0).get(0)[0];   
    12.     
    13. // Here's how we break that expression down step by step.   
    14. // 在這我們怎么樣一步步斷句。   
    15. List<List<int[]>> listOfLists = map.get(key);   
    16. List<int[]> listOfIntArrays = listOfLists.get(0);   
    17. int[] array = listOfIntArrays.get(0);   
    18. int element = array[0];  


    In the code above, the get( ) methods of java.util.List<E> and java.util.Map<K,V> return a list or map element of type E and V respectively. Note, however, that generic types can use their variables in more sophisticated ways. Look up List<E> in the reference section of this book, and you'll find that its iterator( ) method is declared to return an Iterator<E>. That is, the method returns an instance of a parameterized type whose actual type parameter is the same as the actual type parameter of the list. To illustrate this concretely, here is a way to obtain the first element of a List<String> without calling get(0).

    在上面的代碼里, java.util.List<E> 和 java.util.Map<K,V> 的 get() 方法返回一個 list 或是類型分別為 E 和 V 的 map 。但是注意,這些泛類型能用更高級的方式表示他們的變量。參見本書有關 List<E> 的參考說明,你將發(fā)現(xiàn)它的 iterator() 方法被聲明成返回一個 Iterator<E> 類型。那就是,方法返回一個參數(shù)化類型的實例,它的實際泛型參數(shù)和 list 的實際泛型參數(shù)相同。為了具體證明這一點,這有一個方法可以得到 List<String> 的第一個元素而不用調用 get(0) 方法
    Java代碼 復制代碼
    1. List<String> words = // ...initialized elsewhere...  ...其他什么地方初始化...   
    2. Iterator<String> iterator = words.iterator();   
    3. String firstword = iterator.next();  


    4.1.2. Understanding Generic Types
    4.1.2.理解泛類型
    This section delves deeper into the details of generic type usage, explaining the following topics:

    ·         The consequences of using generic types without type parameters

    ·         The parameterized type hierarchy

    ·         A hole in the compile-time type safety of generic types and a patch to ensure runtime type safety

    ·         Why arrays of parameterized types are not typesafe

    這部分將深入 generic type 的詳細用法,簡述以下主題:

    應用沒有泛型參數(shù)的泛類型的結果
    參數(shù)化類型的層次
    一個編譯期的泛類型漏洞和一個保證運行期類型安全的補救辦法
    為什么數(shù)組的參數(shù)化類型是不安全的
    4.1.2.1 Raw types and unchecked warnings
    4.1.2.1原始類型和未檢查的警告

    Even though the Java collection classes have been modified to take advantage of generics, you are not required to specify type parameters to use them. A generic type used without type parameters is known as a raw type. Existing pre-5.0 code continues to work: you simply write all the casts that you're already used to writing, and you put up with some pestering from the compiler. Consider the following code that stores objects of mixed types into a raw List:

    盡管 Java Collection類引入了泛型的優(yōu)點,但是你不需要在用它們的時候指明泛型參數(shù)。沒有泛型參數(shù)的泛類型將作為原始類型。現(xiàn)有的 5.0 以前的代碼可以繼續(xù)工作:你可以象以前一樣簡單的寫所有的造型轉換,然后忍受一些編譯器的糾纏。思考下面用原始 List 存儲混合類型對象的代碼:
    Java代碼 復制代碼
    1. List l = new ArrayList();   
    2. l.add("hello");     
    3. l.add(new Integer(123));   
    4. Object o = l.get(0);  


    This code works fine in Java 1.4. If we compile it using Java 5.0, however, javac compiles the code but prints this complaint:

    在Java 1.4下,這些代碼會工作的很好。但如果用 Java 5.0 編譯, javac 編譯代碼但會列出這個抱怨:

    Note: Test.java uses unchecked or unsafe operations.
    Note: Recompile with -Xlint:unchecked for details.
    注意:Test.java 使用了一個未檢查或是不安全的操作。
    注意:重新用 -Xlint:unchecked 參數(shù)編譯查看詳細信息。


    When we recompile with the -Xlint option as suggested, we see these warnings:

    當我們用建議的 -Xlint 選項編譯后,看到了這樣的警告:
    Java代碼 復制代碼
    1. Test.java:6: warning: [unchecked]   
    2.     unchecked call to add(E) as a member of the raw type java.util.List   
    3.         l.add("hello");     
    4.          ^   
    5. Test.java:7: warning: [unchecked]   
    6.     unchecked call to add(E) as a member of the raw type java.util.List   
    7.         l.add(new Integer(123));   
    8.          ^  


    The compiler warns us about the add( ) calls because it cannot ensure that the values being added to the list have the correct types. It is letting us know that because we've used a raw type, it cannot verify that our code is typesafe. Note that the call to get( ) is okay because it is extracting an element that is already safely in the list.

    編譯器給了我們關于調用 add() 方法的警告,因為它不能確定被增加到 list 中的值有正確的類型。這讓我們知道我們用的是一個原始類型,它不能驗證我們的代碼是安全的。注意, get() 方法的調用是對的,因為它正在析取的元素已經(jīng)安全的存儲在 list 中了。

    If you get unchecked warnings on files that do not use any of the new Java 5.0 features, you can simply compile them with the -source 1.4 flag, and the compiler won't complain. If you can't do that, you can ignore the warnings, suppress them with an @SuppressWarnings("unchecked") annotation (see Section 4.3 later in this chapter) or upgrade your code to specify a type parameter.[2] The following code, for example, compiles with no warnings and still allows you to add objects of mixed types to the list:

    如果你的文件因為沒有用到 Java 5.0 的新特性,而得到 unchecked 警告;你可以簡單用的加 -source 1.4 參數(shù)編譯,這樣編譯器將不再抱怨。如果你不那樣做,你可以忽略這些警告,也可用 annotation (參見本章稍后的4.3部分)中的 @SuppressWarnings("uncheckd") 壓制這些警告,或者,用泛型參數(shù)更新你的代碼。例如下面的代碼,當有你增加混合對象到 list 時,編譯器將不再發(fā)出警告:

    [2] At the time of this writing, javac does not yet honor the @SuppressWarnings annotation. It is expected to do so in Java 5.1.

    [2] 就在本書寫作時 ,javac 還不能兌現(xiàn) annotation 的@SuppressWarnings操作。它將可以在Java 5.1版本中實現(xiàn)。
    Java代碼 復制代碼
    1. List<Object> l = new ArrayList<Object>();   
    2. l.add("hello");     
    3. l.add(123);              // autoboxing 自動裝箱   
    4. Object o = l.get(0);  


    4.1.2.2 The generic type hierarchy
    parameterized types form a type hierarchy, just as normal types do. The hierarchy is based on the base type, however, and not on the type of the parameters. Here are some experiments you can try:

    4.1.2.2 參數(shù)化類型的層次結構

    參數(shù)化類型形成了一個典型的層次結構,就象通常類型一樣的。但是這種分層是基于泛型參數(shù)的類型的,而不是基于參數(shù)化類型變量的類型的。這里有些試驗你可以試一下
    Java代碼 復制代碼
    1. ArrayList<Integer> l = new ArrayList<Integer>();   
    2. List<Integer> m = l;                            // okay   
    3. Collection<Integer> n = l;                      // okay   
    4. ArrayList<Number> o = l;                        // error   
    5. Collection<Object> p = (Collection<Object>)l;   // error, even with cast    
    6.                                                 // 錯誤,發(fā)生在造型那里  


    A List<Integer> is a Collection<Integer>, but it is not a List<Object>. This is nonintuitive, and it is important to understand why generics work this way. Consider this code:

    一個 List<integer> 是一個 Collection<Ineger> ,但不是 List<Object> 。這個不太直觀,但對于理解泛型是如何工作又是非常重要的。思考下面的代碼
    Java代碼 復制代碼
    1. List<Integer> li = new ArrayList<Integer>();   
    2. li.add(123);   
    3.     
    4. // The line below will not compile.  But for the purposes of this   
    5. // thought-experiment, assume that it does compile and see how much   
    6. // trouble we get ourselves into.   
    7. // 下面的這行是不能編譯的。但是依照我們通常的經(jīng)驗和觀點,假定它能編譯,看看   
    8. // 會有什么樣的麻煩   
    9. List<Object> lo = li;     
    10.     
    11. // Now we can retrieve elements of the list as Object instead of Integer   
    12. // 現(xiàn)在我用 Object 檢索 list 中的元素,而不是用Integer   
    13. Object number = lo.get(0);   
    14.     
    15. // But what about this?   
    16. // 但這是什么?   
    17. lo.add("hello world");   
    18.     
    19. // If the line above is allowed then the line below throws ClassCastException   
    20. // 如果上面這行是對的,那么下面一行會拋出 ClassCastException 異常   
    21. Integer i = li.get(1);  // Can't cast a String to Integer!  



    This then is the reason that a List<Integer> is not a List<Object>, even though all elements of a List<Integer> are in fact instances of Object. If the conversion to List<Object> were allowed, non-Integer objects could be added to the list.

    這就是為什么 List<Integer> 不是 List<Object> ,雖說所有的 List<Integer> 元素是 Object 的實例。如果這種轉化成 List<Object> 的操作是允許的,那么 non-Integer 的對象就會被允許加入到 list 中。

    4.1.2.3 Runtime type safety
    As we've seen, a List<X> cannot be converted to a List<Y>, even when X can be converted to Y. A List<X> can be converted to a List, however, so that you can pass it to a legacy method that expects an argument of that type and has not been updated for generics.

    4.1.2.3 運行期安全

    正如我們看到的, List<X> 不能被轉化成 List<Y> ,盡管 X 能被轉化成 Y 。但是 List<X> 能被轉化成 List ,因此你可以通過這個方式處理遺留的代碼(有那種泛型參數(shù)不能升級為泛型的代碼)

    This ability to convert parameterized types to nonparameterized types is essential for backward compatibility, but it does open up a hole in the type safety system that generics offer:

    這種轉化參數(shù)化類型為非參數(shù)化類型的能力是最基本的向后兼容,但這也給具有泛型的系統(tǒng)帶來了一個類型安全漏洞。
    Java代碼 復制代碼
    1. // Here's a basic parameterized list.   
    2. // 這是一個基本的參數(shù)化類型類型的 list 。   
    3. List<Integer> li = new ArrayList<Integer>();   
    4.     
    5. // It is legal to assign a parameterized type to a nonparameterized variable   
    6. // 這樣把一個參數(shù)化類型賦給一個非參數(shù)化類型變量是合法的。   
    7. List l = li;      
    8.     
    9. // This line is a bug, but it compiles and runs.   
    10. // The Java 5.0 compiler will issue an unchecked warning about it.   
    11. // If it appeared as part of a legacy class compiled with Java 1.4, however,   
    12. // then we'd never even get the warning.     
    13. // 這行是個 bug ,但是可以編譯運行。   
    14. // Java 5.0 會發(fā)布一個 unchecked 警告信息   
    15. // 但是,如果用 Java 1.4 編譯遺留的代碼,不會有任何的警告。   
    16. l.add("hello");   
    17.     
    18. // This line compiles without warning but throws ClassCastException at runtime.   
    19. // Note that the failure can occur far away from the actual bug.   
    20. // 這行編譯沒問題,但是會在運行時拋出 ClassCastException 異常   
    21. // 注意這個錯誤發(fā)現(xiàn)的地方,可能會遠離它發(fā)生的實際位置    
    22. Integer i = li.get(0);  


    Generics provide compile-time type safety only. If you compile all your code with the Java 5.0 compiler and do not get any unchecked warnings, these compile-time checks are enough to ensure that your code is also typesafe at runtime. But if you have unchecked warnings or are working with legacy code that manipulates your collections as raw types, you may want to take additional steps to ensure type safety at runtime. You can do this with methods like checkedList() and checkedMap( ) of java.util.Collections. These methods enclose your collection in a wrapper collection that performs runtime type checks to ensure that only values of the correct type are added to the collection. For example, we could prevent the type safety hole shown above like this:

    泛型僅提供了編譯期的類型安全檢查。如果你用 Java 5.0 編譯代碼并且沒有任何的 unchecked 警告,那么這些編譯的檢查能夠保證你的代碼也在運行期是安全的。但是如果你收到 unchecked 警告,或是用了遺留下來的代碼(用原始的類型操作Collection),你可能想用些附加的步驟來確保運行期的類型安全。你可以用 java.util.Collections 的這些方法 checkedList() 和 checkedMap() 來做。這些方法封裝你的Collection到一個包裝的Collection中,它執(zhí)行運行期的檢查確保正確類型的值被加入到你的Collection中。例如,我們可這樣阻止類型安全的漏洞:
    Java代碼 復制代碼
    1. // Here's a basic parameterized list.   
    2. // 這是一個基本的參數(shù)化類型的 list 。   
    3. List<Integer> li = new ArrayList<Integer>();   
    4.     
    5. // Wrap it for runtime type safety   
    6. // 為了運行期的安全,我們包裝了它   
    7. List<Integer> cli = Collections.checkedList(li, Integer.class);   
    8.     
    9. // Now widen the checked list to the raw type   
    10. // 現(xiàn)在放到這個 checked 的 list 到原始類型   
    11. List l = cli;      
    12.     
    13. // This line compiles but fails at runtime with a ClassCastException.   
    14. // 這行可編譯,但是運行期會拋出 ClassCastException 異常。   
    15. // The exception occurs exactly where the bug is, rather than far away   
    16. // 這個異常能夠定位 bug 的位置,而不是遠離它實際的位置   
    17. l.add("hello");   
    18.    

    4.1.2.4 Arrays of generic type
    4.1.2.4 關于數(shù)組的參數(shù)化類型

    Arrays require special consideration when working with generic types. Recall that an array of type S[ ] is also of type T[], if T is a superclass (or interface) of S. Because of this, the Java interpreter must perform a runtime check every time you store an object in an array to ensure that the runtime type of the object and of the array are compatible. For example, the following code fails this runtime check and throws an ArrayStoreException:

    當數(shù)組遇到泛類型時,我們需要特別的考慮?;叵胍粋€類型 S[] 的數(shù)組也是類型為 T[]  的數(shù)組,如果 T 是 S 的超類(或是接口)。因此,必須每當你存儲一個對象到一個數(shù)組時,Java 的解析器就會執(zhí)行一個運行期檢查,以確保運行時放入的對象的類型和數(shù)組的類型相容。例如,下面的代碼在運行期檢查是失敗的,并且拋出一個 ArrayStoreException 異常:
    Java代碼 復制代碼
    1. String[] words = new String[10];   
    2. Object[] objs = words;   
    3. objs[0] = 1;  // 1 autoboxed to an Integer, throws ArrayStoreException    
    4.            // 1 被自動裝箱到 Integer,拋出ArrayStoreException 異常   
    5.    


    Although the compile-time type of objs is Object[], its runtime type is String[ ], and it is not legal to store an Integer in it.

    雖然編譯時 objs 的類型是 Object[],但在運行時的類型是 String[] ,并非法的把 Integer 值放入其中。

    When we work with generic types, the runtime check for array store exceptions is no longer sufficient because a check performed at runtime does not have access to the compile-time type parameter information. Consider this (hypothetical) code:

    當我們應用泛類型時,運行期關于數(shù)組存儲異常的檢測已經(jīng)不能滿足需要,因為一個運行期的檢測不能讀取編譯期的泛型參數(shù)信息??紤]下面的代碼(假設可以執(zhí)行):
    Java代碼 復制代碼
    1. List<String>[] wordlists = new ArrayList<String>[10];   
    2. ArrayList<Integer> ali = new ArrayList<Integer>();   
    3. ali.add(123);   
    4. Object[] objs = wordlists;   
    5. objs[0] = ali;                       // No ArrayStoreException //沒有 ArrayStoreException 異常   
    6. String s = wordlists[0].get(0);         // ClassCastException!  //ClassCastException 異常   
    7.    


    If the code above were allowed, the runtime array store check would succeed: without compile-time type parameters, the code simply stores an ArrayList into an ArrayList[] array, which is perfectly legal. Since the compiler can't prevent you from defeating type safety in this way, it instead prevents you from creating any array of generic type. The scenario above can never occur because the compiler will refuse to compile the first line.

    如果上面的代碼可以執(zhí)行,運行時數(shù)組存儲檢查將是成功的;沒有編譯時的泛型參數(shù),這段代碼簡單的把一個 ArrayList 存到 ArrayList[] 數(shù)組中,那都是非常正確的。因為編譯器不能從這個方式阻止你破壞類型安全,它只能阻止你創(chuàng)建任何的參數(shù)化類型類型數(shù)組。其實上面的一幕是不會發(fā)生的,因為編譯器將會拒絕第一個行的編譯。

    Note that this is not a blanket restriction on using arrays with generics; it is just a restriction on creating arrays of parameterized type. We'll return to this issue when we look at how to write generic methods.

    注意這不是完全禁止數(shù)組應用泛型;這僅是禁止用參數(shù)化類型創(chuàng)建數(shù)組。當看過怎樣寫泛型方法后,會回到這個話題。

    4.1.3. Type Parameter Wildcards
    4.1.3. 泛型參數(shù)通配符

    Suppose we want to write a method to display the elements of a List.[3] Before List was a generic type, we'd just write code like this:

    假設我們想寫一個顯示 List 元素的方法。[3]在 List 是應用泛類型前,我們僅需要這樣寫代碼:

    [3] The three printList() methods shown in this section ignore the fact that the List implementations classes in java.util all provide working toString() methods. Notice also that the methods assume that the List implements RandomAccess and provides very poor performance on LinkedList instances.

    [3] 這段的三個 priintList() 方法忽略了一個前提,就是 List 在 java.util 包中的實現(xiàn)類都實現(xiàn)了 toString() 方法。注意這些方法也假定 List 實現(xiàn)了 RandomAccess 功能和提供了比較弱的 LinkedList 實例的性能。
    Java代碼 復制代碼
    1. public static void printList(PrintWriter out, List list) {   
    2.     for(int i=0, n=list.size(); i < n; i++) {   
    3.         if (i > 0) out.print(", ");   
    4.         out.print(list.get(i).toString());   
    5.     }   
    6. }   
    7.    

    In Java 5.0, List is a generic type, and, if we try to compile this method, we'll get unchecked warnings. In order to get rid of those warnings, you might be tempted to modify the method as follows:

    在 Java 5.0 中, List 是一個泛類型,并且,如果你試著編譯這個方法,將會得到 unchecked 警告。為了除去這些警告,你可能很想修改方法成下面的樣子:
    Java代碼 復制代碼
    1. public static void printList(PrintWriter out, List<Object> list) {   
    2.     for(int i=0, n=list.size(); i < n; i++) {   
    3.         if (i > 0) out.print(", ");   
    4.         out.print(list.get(i).toString());   
    5.     }   
    6. }   
    7.    


    This code compiles without warnings but isn't very useful because the only lists that can be passed to it are lists explicitly declared of type List<Object>. Remember that List<String> and List<Integer> (for example) cannot be widened or cast to List<Object>. What we really want is a typesafe printList() method to which we can pass any List, regardless of how it has been parameterized. The solution is to use a wildcard as the type parameter. The method would then be written like this:

    這代碼這么編譯不會有警告,但沒太大用處。因為僅當傳遞的是 List<Object> 類型的值給 list 時可用。還記得那個 List<String> 和 List<integer> 的例子吧,不可以放大造型成 List<Object>。怎么樣才可以構建一個可以傳任何類型的 List 的printList() 方法呢,而不關心這個 List 是否被泛化。解決的方法就是用泛型參數(shù)通配符。這個方法可以這么寫:
    Java代碼 復制代碼
    1. public static void printList(PrintWriter out, List<?> list) {   
    2.     for(int i=0, n=list.size(); i < n; i++) {   
    3.         if (i > 0) out.print(", ");   
    4.         Object o = list.get(i);   
    5.         out.print(o.toString());   
    6.     }   
    7. }   
    8.    


    This version of the method compiles without warnings and can be used the way we want it to be used. The ? wildcard represents an unknown type, and the type List<?> is read as "List of unknown."

    這個版本的方法可以順利編譯沒有警告,并且做你想做的用途。這個"?"通配符表示不知道具體類型,這個類型 List<?> 讀作"List of unknown"。

    As a general rule, if a type is generic and you don't know or don't care about the value of the type variable, you should always use a ? wildcard instead of using a raw type. Raw types are allowed only for backward compatibility and should be used only in legacy code. Note, however, that you cannot use a wildcard when invoking a constructor. The following code is not legal:

    作為泛化規(guī)則,如果一個類型是泛化的并且你不知道或是不關心泛型變量的值,你總是應該用 ? 通配符替換一個原始類型。原始類型僅應用在向后兼容和遺留的代碼中。注意,但是你不可以在構造方法中使用。下面的代碼是非法的:
    Java代碼 復制代碼
    1. List<?> l = new ArrayList<?>();   
    2.    


    There is no sense in creating a List of unknown type. If you are creating it, you should know what kind of elements it will hold. You may later want to pass such a list to a method that does not care about its element type, but you need to specify an element type when you create it. If what you really want is a List that can hold any type of object, do this:

    不可以用未知的類型創(chuàng)建一個 List 實例,如果你創(chuàng)建一個實例,你應該知道可以容納的元素類型。接下來,你可能想傳一個 list 到方法中,并不關心 list 中元素的類型,可惜你必需在創(chuàng)建它的時候指定一個元素的類型。如果你真得想創(chuàng)建一個可容納任何類型對象的 List ,你可這么做:
    Java代碼 復制代碼
    1. List<Object> l = new ArrayList<Object>();  


    It should be clear from the printList( ) variants above that a List<?> is not the same thing as a List<Object> and that neither is the same thing as a raw List. A List<?> has two important properties that result from the use of a wildcard. First, consider methods like get() that are declared to return a value of the same type as the type parameter. In this case, that type is unknown, so these methods return an Object. Since all we need to do with the object is invoke its toString() method, this is fine for our needs.

    這是非常清楚的,變種方法printList() 中的 List<?> 和 List<object> 是不同的。而且它們和原始類型的 List 一點也不一樣。List<?>有兩個重要的屬性。首先,是用了通配符的結果。思考 get() 這樣的方法,它被聲明成返回值的類型和泛型參數(shù)指定的類型相同。在這個例子中,類型未知因此方法返回 Object 。既然我們所有要做的是調用 object 的 toString() 方法,那它一定會如我們所愿。

    Second, consider List methods such as add() that are declared to accept an argument whose type is specified by the type parameter. This is the more surprising case: when the type parameter is unknown, the compiler does not let you invoke any methods that have a parameter of the unknown type because it cannot check that you are passing an appropriate value. A List<?> is effectively read-only since the compiler does not allow us to invoke methods like add( ), set(), and addAll( ).

    第二,思考 List 的 add() 方法,它接受一個由泛型參數(shù)指定類型的參數(shù)。這是個很讓人吃驚的情況:當泛型參數(shù)不未知時,編譯器不會讓我們調用任何方法,因為參數(shù)的類型未知,它不能檢測你傳遞參數(shù)值的類型。List<?> 對僅僅是讀是有效的,因為編譯器不允許我們調用象 add(),set() 和 addAll() 此類的方法。

    4.1.3.1 Bounded wildcards
    4.1.3.1 邊界通配符

    Let's continue now with a slightly more complex variant of our original example. Suppose that we want to write a sumList() method to compute the sum of a list of Number objects. As before, we could use a raw List, but we would give up type safety and have to deal with unchecked warnings from the compiler. Or we could use a List<Number>, but then we wouldn't be able to call the method for a List<Integer> or List<Double>, types we are more likely to use in practice. But if we use a wildcard, we don't actually get the type safety that we want because we have to trust that our method will be called with a List whose type parameter is actually Number or a subclass and not, say, a String. Here's what such a method might look like:

    接著讓我們對最初的例子做個稍微復雜的變化。假設我們需要寫一個 sumList() 方法,來計算一個 Number 類型 list 中元素的的和。在往常,我們用原始類型的 List ,但那會放棄類型安全檢測,必須處理編譯器的 unchecked 警告信息?;蛘呶覀兛梢杂靡粋€ List<Number>類型,但是那樣做我們不能讓方法用 List<Integer> 類型或是 List<Double> 類型,或是我們實際喜歡的類型的參數(shù)值。但是你如果用了通配符,卻不能得到你想要的類型安全。因為我們必須委托調用參數(shù)為 List 類型的方法,它的實際的泛型參數(shù)值可能是 Number 或是它的子類,或者和它根本就不相關,比如說是一個 String 。這有一個這樣的例子,我們可以看一下:
    Java代碼 復制代碼
    1. public static double sumList(List<?> list) {   
    2.     double total = 0.0;   
    3.     for(Object o : list) {   
    4.         Number n = (Number) o;  // A cast is required and may fail //需要造型,但可能會失敗   
    5.         total += n.doubleValue();   
    6.     }   
    7.     return total;   
    8. }  


    To fix this method and make it truly typesafe, we need to use a bounded wildcard that states that the type parameter of the List is an unknown type that is either Number or a subclass of Number. The following code does just what we want:

    為了修訂這個問題,真正做到類型安全,人們需要邊界通配符。情況是這樣的, List 的泛型參數(shù)是 Number 或是它的子類。下面的代碼才是我們想要的:
    Java代碼 復制代碼
    1. public static double sumList(List<? extends Number> list) {   
    2.     double total = 0.0;   
    3.     for(Number n : list) total += n.doubleValue();   
    4.     return total;   
    5. }   
    6.    


    The type List<? extends Number> could be read as "List of unknown descendant of Number." It is important to understand that, in this context, Number is considered a descendant of itself.

    類型 List<? extends Number> 可以讀作"List of unknown descendant of Number.( Number 未知后裔的 List 類型)"。理解這一點是非常重要的。在這個語境中,Number 是自己的后裔。

    Note that the cast is no longer required. We don't know the type of the elements of the list, but we know that they have an "upper bound" of Number so we can extract them from the list as Number objects. The use of a for/in loop obscures the process of extracting elements from a list somewhat. The general rule is that when you use a bounded wildcard with an upper bound, methods (like the get() method of List) that return a value of the type parameter use the upper bound. So if we called list.get( ) instead of using a for/in loop, we'd also get a Number. The prohibition on calling methods like list.add( ) that have arguments of the type parameter type still stands: if the compiler allowed us to call those methods we could add an Integer to a list that was declared to hold only Short values, for example.

    注意,這里不再需要造型。我們不知道 list 元素的類型,但是我們知道他們都有一個"上界"類型是 Number ,因此我們可以把它們當作 Number 的對象拿出來。這里我們用隱式的 for/in 結構處理從 list 中拿到的每個元素。通常的規(guī)則是我們用上界通配符,讓方法(象 list當中的 get() 方法)返回一個是上界泛型參數(shù)指定類型的值。例如,如果我們調用了 list.get() 方法,而不是用 for/in 結構,我會得到一個 Number 對象;但是仍然禁止調用有泛型參數(shù)的 list.add() 方法,如果編譯器允許我們這樣調用方法,我們就可以增加一個 Integer 的對象到容納 Short 類型的 list 當中。

    It is also possible to specify a lower-bounded wildcard using the keyword super instead of extends. This technique has a different impact on what methods can be called. Lower-bounded wildcards are much less commonly used than upper-bounded wildcards, and we discuss them later in the chapter.

    當然你也可以有關鍵字 super 替換 extends 指定一個下界通配符。調用這樣的方法的技術會帶給我們不同的影響。下界通配符不如上界通配符用的多,我們會在章節(jié)的后面討論。

    4.1.4. Writing Generic Types and Methods
    4.1.4.寫泛類型和泛型方法

    Creating a simple generic type is straightforward. First, declare your type variables by enclosing a comma-separated list of their names within angle brackets after the name of the class or interface. You can use those type variables anywhere a type is required in any instance fields or methods of the class. Remember, though, that type variables exist only at compile time, so you can't use a type variable with the runtime operators instanceof and new.

    創(chuàng)建一個簡單的泛類型是容易的。首先,在類名或是接口名后,用封閉的尖括號用逗號隔開聲明一系列泛型變量。你可以在這個類的任何需要類型的地方,把泛型變量作為類型,應用到實例變量或是方法中。但是記住,泛型變量僅存在于編譯期,因此你不能讓泛型變量和運行的 instanceof 操作或是 new 操作連用

    We begin this section with a simple generic type, which we will subsequently refine. This code defines a tree data structure that uses the type variable V to represent the type of the value held in each node of the tree:

    這段開始我們定義了一個簡單的泛類型,隨后我們將重新定義它。代碼定義了一個 tree 結構,用泛型變量 V 表示存儲在 tree 中每個節(jié)點值的類型:
    Java代碼 復制代碼
    1. import java.util.*;   
    2.     
    3. /**  
    4.  * A tree is a data structure that holds values of type V.  
    5.  * Each tree has a single value of type V and can have any number of  
    6.  * branches, each of which is itself a Tree.  
    7.  */  
    8. /**  
    9.  * 一個tree的數(shù)據(jù)結構,容納類型為 V 的值。  
    10.  * 每一個樹有一個獨立的 V 類型的值,可以有一定數(shù)據(jù)的分枝,它們又可以有自己的樹  
    11.  */  
    12. public class Tree<V> {   
    13.     // The value of the tree is of type V.   
    14.       // 這個樹的 vaule 類型是V   
    15.     V value;   
    16.     
    17.     // A Tree<V> can have branches, each of which is also a Tree<V>   
    18.       // 一個 Tree<V> 可以其他分枝,每個分析又都是一個 Tree<V>    
    19.     List<Tree<V>> branches = new ArrayList<Tree<V>>();   
    20.     
    21.     // Here's the constructor.  Note the use of the type variable V.   
    22.       // 這是構造方法。注意這里用的是泛型變量 V    
    23.     public Tree(V value) { this.value = value; }   
    24.     
    25.     // These are instance methods for manipulating the node value and branches.   
    26.     // Note the use of the type variable V in the arguments or return types.   
    27.     // 這些實例方法操作節(jié)點值和分枝。   
    28.     // 注意這里在參數(shù)類型和返回值類型中用了泛型變量 V    
    29.     V getValue() { return value; }   
    30.     void setValue(V value) { this.value = value; }   
    31.     int getNumBranches() { return branches.size(); }   
    32.     Tree<V> getBranch(int n) { return branches.get(n); }   
    33.     void addBranch(Tree<V> branch) { branches.add(branch); }   
    34. }   
    35.    

    As you've probably noticed, the naming convention for type variables is to use a single capital letter. The use of a single letter distinguishes these variables from the names of actual types since real-world types always have longer, more descriptive names. The use of a capital letter is consistent with type naming conventions and distinguishes type variables from local variables, method parameters, and fields, which are sometimes written with a single lowercase letter. Collection classes like those in java.util often use the type variable E for "Element type." When a type variable can represent absolutely anything, T (for Type) and S are used as the most generic type variable names possible (like using i and j as loop variables).

    可能你已經(jīng)注意到了,泛型變量的命名約定是用一個大寫字母表示。就是用一個單獨的字母表示的變量去區(qū)別實際類型的變量名,因為真實的類型名總是很長的。一個大寫字母的用法是和類型命名的約定相一致的,并這些泛型變量區(qū)別于局部判變量,方法參數(shù)和實例變量(這些變量有時用一個字母,不過是小寫的)。象在包 java.util 中的Collection類用泛型變量 E 表示" Element type 元素類型"。在所有的泛型變量里,T(表示類型)和 S 可能是用得最多的變量名(就象循環(huán)變量 i 和 j 一樣)。

    Notice that the type variables declared by a generic type can be used only by the instance fields and methods (and nested types) of the type and not by static fields and methods. The reason, of course, is that it is instances of generic types that are parameterized. Static members are shared by all instances and parameterizations of the class, so static members do not have type parameters associated with them. Methods, including static methods, can declare and use their own type parameters, however, and each invocation of such a method can be parameterized differently. We'll cover this later in the chapter.

    注意用泛類型聲明的泛型變量僅被用作實例變量和方法類型(嵌套類型),不可用于靜態(tài)域和靜態(tài)方法。當然,理由是泛類型是實例初始化的。靜態(tài)方法被類的所有實例共享,是類初始化的。因此靜態(tài)方法不能有泛型參數(shù)相關聯(lián)。方法(包括靜態(tài)方法)的聲明和使用可以是自己的泛型參數(shù),不過每次調用的是一個不同參數(shù)化的方法。本章稍后我們會涉及到這個問題。

    4.1.4.1 Type variable bounds
    4.1.4.1 泛型變量邊界

    The type variable V in the declaration above of the TRee<V> class is unconstrained: TRee can be parameterized with absolutely any type. Often we want to place some constraints on the type that can be used: we might want to enforce that a type parameter implements one or more interfaces, or that it is a subclass of a specified class. This can be done by specifying a bound for the type variable. We've already seen upper bounds for wildcards, and upper bounds can also be specified for type variables using a similar syntax. The following code is the tree example rewritten to make tree objects Serializable and Comparable. In order to do this, the example uses a type variable bound to ensure that its value type is also Serializable and Comparable. Note how the addition of the
    Comparable bound on V enables us to write the compareTo() method tree by guaranteeing the existence of a compareTo() method on V.[4]

    在上面 TRee<V> 類中聲明的泛型變量 V 是沒有被約束的: Tree 可以被參數(shù)化成任何其他類型。我們經(jīng)常會給要用的類型一定的約束:我們可能想這么做,讓一個類型實現(xiàn)一個或多個接口,或者是一個指定類的。這個任務可以通過指定泛型變量的邊界完成。我們已經(jīng)見過上界通配符了,它可以用相似的語法被應用到泛型變量上。下面的 tree 代碼應用了 Serializable 和 Comparable 進行了重寫。為了完成任務,這個例子用了一個泛型變量通配符,以保證它的值類型也是 Serializable 和 Comparable的。注意,為了(通過)保證 V 中存在 compareTo() 方法,這種為 Comparable 增加 V 邊界的變化是怎樣讓我們寫一個有 compareTo()方法的 tree 的。

    [4] The bound shown here requires that the value type V is comparable to itself, in other words, that it implements the Comparable interface directly. This rules out the use of types that inherit the Comparable interface from a superclass. We'll consider the Comparable interface in much more detail at the end of this section and present an alternative there.

    這兒的邊界要求值的類型 V 可以和自己比較,換句話說,它直接實現(xiàn)了 Comparable 接口。另外的一個用法是,讓它從超類那里繼承這個 Comparable 接口。我們將在這章結束時更詳細的思考 Comparable 接口,現(xiàn)在這里兩個中選擇哪一種都行。
    Java代碼 復制代碼
    1. import java.io.Serializable;   
    2. import java.util.*;   
    3.     
    4. public class Tree<V extends Serializable & Comparable<V>>   
    5.     implements Serializable, Comparable<Tree<V>>   
    6. {   
    7.     V value;   
    8.     List<Tree<V>> branches = new ArrayList<Tree<V>>();   
    9.     
    10.     public Tree(V value) { this.value = value; }   
    11.     
    12.     // Instance methods   
    13.     // 實例方法   
    14.     V getValue() { return value; }   
    15.     void setValue(V value) { this.value = value; }   
    16.     int getNumBranches() { return branches.size(); }   
    17.     Tree<V> getBranch(int n) { return branches.get(n); }   
    18.     void addBranch(Tree<V> branch) { branches.add(branch); }   
    19.     
    20.     // This method is a nonrecursive implementation of Comparable<Tree<V>>   
    21.     // It only compares the value of this node and ignores branches.   
    22.     // 這里沒有循環(huán)實現(xiàn) Comparable<Tree<V>> 接口,只是比較這個節(jié)點的值,而忽略了分枝   
    23.     public int compareTo(Tree<V> that) {   
    24.         if (this.value == null && that.value == nullreturn 0;   
    25.         if (this.value == nullreturn -1;   
    26.         if (that.value == nullreturn 1;   
    27.         return this.value.compareTo(that.value);   
    28.     }   
    29.     
    30.     // javac -Xlint warns us if we omit this field in a Serializable class   
    31.     // 如果在一個 Serializable 的類中省略這個域,如此編譯 :javac -Xlint ,會得到警告   
    32.     private static final long serialVersionUID = 833546143621133467L;   
    33. }   
    34.    


    The bounds of a type variable are expressed by following the name of the variable with the word extends and a list of types (which may themselves be parameterized, as Comparable is). Note that with more than one bound, as in this case, the bound types are separated with an ampersand rather than a comma. Commas are used to separate type variables and would be ambiguous if used to separate type variable bounds as well. A type variable can have any number of bounds, including any number of interfaces and at most one class.

    泛型變量邊界通過其后的變量名、 extends 和類型列表(它們自己是可參數(shù)化的,比如 Comparable 就是)表達。注意,這個例子里是多個邊界而不是一個,邊界類型用之間用"&"分隔而不是","。","被用作泛型變量的分隔,再用作泛型變量邊界分隔會產(chǎn)生歧義。一個泛型變量可以有相當數(shù)量的邊界,包括一定量的接口和至多一個類。
     

    4.1.4.2 Wildcards in generic types
    4.1.4.2 泛類型中的通配符

    Earlier in the chapter we saw examples using wildcards and bounded wildcards in methods that manipulated parameterized types. They are also useful in generic types. Our current design of the tree class requires the value object of every node to have exactly the same type, V. Perhaps this is too strict, and we should allow branches of a tree to have values that are a subtype of V instead of requiring V itself. This version of the tree class (minus the Comparable and Serializable implementation) is more flexible:

    本章早些時候,我們有例子用了通配符和在方法中操控參數(shù)化類型的邊界通配符。它們都是非常有用的 generic type 。當前我們設計 tree 類,需要每一個節(jié)點值的對象類型精確的是 V ??赡苓@太過苛刻了,我們應該允許 tree 的分枝可以容納類型 V 的子類型,不一定是 V 自己。下面這個 tree 的版本就相當靈活的(除去了 Comparable 和 Serializable)。
    Java代碼 復制代碼
    1. public class Tree<V> {   
    2.     // These fields hold the value and the branches   
    3.     // 這個 value 域包含分枝   
    4.     V value;   
    5.     List<Tree<? extends V>> branches = new ArrayList<Tree<? extends V>>();   
    6.     
    7.     // Here's a constructor   
    8.     // 這是構造方法   
    9.     public Tree(V value) { this.value = value; }   
    10.     
    11.     // These are instance methods for manipulating value and branches   
    12.     // 這是操控 value 和分枝的實例方法   
    13.     V getValue() { return value; }   
    14.     void setValue(V value) { this.value = value; }   
    15.     int getNumBranches() { return branches.size(); }   
    16.     Tree<? extends V> getBranch(int n) { return branches.get(n); }   
    17.     void addBranch(Tree<? extends V> branch) { branches.add(branch); }   
    18. }  


    The use of bounded wildcards for the branch type allow us to add a tree<Integer>, for example, as a branch of a tree<Number>:
    這分枝中邊界通配符的用法允許你增加 tree<Integer> 對象,例如,一個分枝是 tree<Number> 類型的:
    Java代碼 復制代碼
    1. Tree<Number> t = new Tree<Number>(0);  // Note autoboxing //這是自動裝箱   
    2. t.addBranch(new Tree<Integer>(1));     // int 1 autoboxed to Integer //int型的 1 自動轉換成 Integer   
    3.    


    If we query the branch with the getBranch( ) method, the value type of the returned branch is unknown, and we must use a wildcard to express this. The next two lines are legal, but the third is not:

    如果我們用方法 getBranch() 檢索分枝,分枝返回值的類型是未知,我們必須用通配符表示。下面前兩句是合法的,而第三句不是:
    Java代碼 復制代碼
    1. Tree<? extends Number> b = t.getBranch(0);   
    2. Tree<?> b2 = t.getBranch(0);   
    3. Tree<Number> b3 = t.getBranch(0);  // compilation error // 編譯錯誤   
    4.    


    When we query a branch like this, we don't know the precise type of the value, but we do still have an upper bound on the value type, so we can do this:

    當我們這樣檢索分枝時,是不知道確切值的類型的,但我們仍然有一個向上的邊界類型,因此我們可以這么做:
    Java代碼 復制代碼
    1. Tree<? extends Number> b = t.getBranch(0);   
    2. Number value = b.getValue();  


    What we cannot do, however, is set the value of the branch, or add a new branch to that branch. As explained earlier in the chapter, the existence of the upper bound does not change the fact that the value type is unknown. The compiler does not have enough information to allow us to safely pass a value to setValue() or a new branch (which includes a value type) to addBranch(). Both of these lines of code are illegal:

    但什么是我們不能做的呢,就是為分枝賦值或是增加一個新元素到分枝時,是不可以的。就如我們較早解釋的那樣,向上邊界不可以改變的一事實是:值的類型是未知的。編譯器沒有足夠的信息允許你傳一個值,到 setValue() 方法或是增加新分枝(其中包括了值的類型)的 addBranch() 方法中。下面兩行是不合法的:
    Java代碼 復制代碼
    1. b.setValue(3.0); // Illegal, value type is unknown // 非法,值類型未知   
    2. b.addBranch(new Tree<Double>(Math.PI));   
    3.    

    This example has illustrated a typical trade-off in the design of a generic type: using a bounded wildcard made the data structure more flexible but reduced our ability to safely use some of its methods. Whether or not this was a good design is probably a matter of context. In general, generic types are more difficult to design well. Fortunately, most of us will use the preexisting generic types in the java.util package much more frequently than we will have to create our own.

    這個例子已經(jīng)簡述了一個典型的折衷泛類型設計方法:用一個邊界通配符構造一個數(shù)據(jù)結構是非常靈活的,但是降低了一些它自己方法的安全性。幸好,我們多數(shù)時候使用 java.util 包中的泛類型而不是我們自己創(chuàng)建的。

    4.1.4.3 Generic methods
    4.1.4.3 泛型方法

    As noted earlier, the type variables of a generic type can be used only in the instance members of the type, not in the static members. Like instance methods, however, static methods can use wildcards. And although static methods cannot use the type variables of their containing class, they can declare their own type variables. When a method declares its own type variable, it is called a generic method.

    正如前面所釋的,一個泛類型的泛型變量僅可以用作類的實例成員,不能是靜態(tài)成員。但是象實例方法,靜態(tài)方法可以用通配符。盡管靜態(tài)方法不能使用它們所在類的泛型變量,但是它們能聲明自己的泛型變量。當一個方法聲明自己的泛型變量時,這個方法叫作:generic method。

    Here is a static method that could be added to the Tree class. It is not a generic method but uses a bounded wildcard much like the sumList() method we saw earlier in the chapter:

    這個方法可以增加到 Tree 類中。它不是 generic method ,但是用了邊界通配符,就象本章前些時候看到的 sumList() 方法一樣:
    Java代碼 復制代碼
    1. /** Recursively compute the sum of the values of all nodes on the tree */  
    2. /** 遞歸計算 tree 中所有值的和    
    3. public static double sum(Tree<? extends Number> t) {   
    4.     double total = t.value.doubleValue();   
    5.     for(Tree<? extends Number> b : t.branches) total += sum(b);   
    6.     return total;   
    7. }   
    8.    

    This method could also be rewritten as a generic method by declaring a type variable to express the upper bound imposed by the wildcard:

    這個方法用泛型變量,重寫成了泛型方法,來實現(xiàn)通配符版的功能。
    Java代碼 復制代碼
    1. public static <N extends Number> double sum(Tree<N> t) {   
    2.     N value = t.value;   
    3.     double total = value.doubleValue();   
    4.     for(Tree<? extends N> b : t.branches) total += sum(b);   
    5.     return total;   
    6. }   
    7.    


    The generic version of sum() is no simpler than the wildcard version and the declaration of the type variable does not gain us anything. In a case like this, the wildcard solution is typically preferred over the generic solution. Generic methods are required where a single type variable is used to express a relationship between two parameters or between a parameter and a return value. The following method is an example:

    這個泛型版的 sum() 不比通配符版的簡單,并沒有通過聲明泛型變量得到什么好處。就象這個例子中,通配符版的解決方案要好于泛型版的。泛型方法通常 適用于只有一個泛型變量,表示兩個參數(shù)之間的聯(lián)系,或是表示一個參數(shù)和一個值之間的關系。就象下面的代碼:
    Java代碼 復制代碼
    1. // This method returns the largest of two trees, where tree size   
    2. // is computed by the sum() method.  The type variable ensures that    
    3. // both trees have the same value type and that both can be passed to sum().   
    4. // 當調用了 sum()方法后,這個方法返回兩個樹中最大的那個。這個泛型變量使得兩個 tree    
    5. // 有相同類型的值,可以使用 sum() 方法。   
    6. public static <N extends Number> Tree<N> max(Tree<N> t, Tree<N> u) {   
    7.     double ts = sum(t);   
    8.     double us = sum(u);   
    9.     if (ts > us) return t;   
    10.     else return u;   
    11. }   
    12.    


    This method uses the type variable N to express the constraint that both arguments and the return value have the same type parameter and that that type parameter is Number or a subclass.

    這個方法用泛型變量 N 表示兩個參數(shù)之間的約束,并且返回值有相同的泛型參數(shù)表示的類型,而且泛型參數(shù)要么是 Number 或是它的子類。

    It could be argued that constraining both arguments to have the same value type is too restrictive and that we should be allowed to call the max( ) method on a tree<Integer> and a tree<Double>. One way to express this is to use two unrelated type variables to represent the two unrelated value types. Note, however, that we cannot use either variable in the return type of the method and must use a wildcard there:

    對于兩個參數(shù)必須有兩相同的類型是不是太苛刻了,就這一點是有爭議的。我們應該允許用 tree<Integer> 和 tree<Double> 的參數(shù)調用 max()方法。一個辦法是用兩個無關的泛型變量表示兩個無關的值類型。但是,注意這里方法不能再用變量返回,而用一個通配符:

    Java代碼 復制代碼
    1.     
    2. public static <N extends Number, M extends Number>   
    3.     Tree<? extends Number> max(Tree<N> t, Tree<M> u) {...}   
    4.    


    Since the two type variables N and M have no relation to each other, and since each is used in only a single place in the signature, they offer no advantage over bounded wildcards. The method is better written this way:

    因為兩個泛型變量 N 和 M 彼此不相關,每次只能返回一個類型標識。這不比邊界通配符有優(yōu)越性。這個方法這么寫更好:
    Java代碼 復制代碼
    1. public static Tree<? extends Number> max(Tree<? extends Number> t,   
    2.                                          Tree<? extends Number> u) {...}   
    3.    

    All the examples of generic methods shown here have been static methods. This is not a requirement: instance methods can declare their own type variables as well.

    這例子中所述的所有泛型方法都是靜態(tài)方法。這不是強求的:實例方法也能聲明自己的泛型變量。

    4.1.4.4 Invoking generic methods
    4.1.4.4 調用 generic method

    When you use a generic type, you must specify the actual type parameters to be substituted for its type variables. The same is not generally true for generic methods: the compiler can almost always figure out the correct parameterization of a generic method based on the arguments you pass to the method. Consider the max() method defined above, for instance:

    如果你用了一個泛類型 ,你必須用它自己實際的泛型參數(shù)替換。但這對泛型方法卻不一定:編譯器幾乎總是能算出傳給泛型方法的參數(shù)的真實類型??紤]上面定義的 max() 方法,例如:
    Java代碼 復制代碼
    1. public static <N extends Number> Tree<N> max(Tree<N> t, Tree<N> u) {...}   
    2.    


    You need not specify N when you invoke this method because N is implicitly specified in the values of the method arguments t and u. In the following code, for example, the compiler determines that N is Integer:

    當你調用這個方法的時候不需要確定 N 的值。因為 N 被方法參數(shù) t 和 u 隱含指定了。例如下面的代碼,編譯器斷定 N 是 Integer 類型的:
    Java代碼 復制代碼
    1. Tree<Integer> x = new Tree<Integer>(1);   
    2. Tree<Integer> y = new Tree<Integer>(2);   
    3. Tree<Integer> z = Tree.max(x, y);   
    4.    

    The process the compiler uses to determine the type parameters for a generic method is called type inference. Type inference is relatively intuitive to understand, but the actual algorithm the compiler must use is surprisingly complex and is well beyond the scope of this book. Complete details are in Chapter 15 of The Java Language Specification, Third Edition.

    編譯器這種斷定被調泛型方法泛型參數(shù)的過程叫做 type inerence (類型推定)。類型推定是相對直觀和容易理解的,但編譯器實現(xiàn)時的算法卻是令人吃驚的復雜,這個討論已經(jīng)走出了本書的討論范圍。詳細內容你可以參照 The Java Language Specification, Third Edition 的15章。

    Let's look at a slightly more complex version of type inference. Consider this method:

    讓我看一個稍微復雜版本的類型推定??紤]下面的方法:
    Java代碼 復制代碼
    1. public class Util {   
    2.     /** Set all elements of a to the value v; return a. */  
    3.     /** 用 V 類型賦所有值;返回 a */  
    4.     public static <T> T[] fill(T[] a, T v) {   
    5.         for(int i = 0; i < a.length; i++) a[i] = v;   
    6.         return a;   
    7.     }   
    8. }   
    9.    

    Here are two invocations of the method:

    這有對這個方法的兩種不同調用:
    Java代碼 復制代碼
    1. Boolean[] booleans = Util.fill(new Boolean[100], Boolean.TRUE);   
    2. Object o = Util.fill(new Number[5], new Integer(42));  


    In the first invocation, the compiler can easily determine that T is Boolean. In the second invocation, the compiler determines that T is Number.

    前面的調用,編譯器很容易判斷 T 是 Boolean 類型的。第二種調用,編譯器斷定 T 是 Number 類型的。

    In very rare circumstances you may need to explicitly specify the type parameters for a generic method. This is sometimes necessary, for example, when a generic method expects no arguments. Consider the java.util.Collections.emptySet( ) method: it returns a set with no elements, but unlike the Collections.singleton( ) method (you can look these up in the reference section), it takes no arguments that would specify the type parameter for the returned set. You can specify the type parameter explicitly by placing it in angle brackets before the method name:

    在非常少的情況下,你需要為泛型方法顯示指定泛型參數(shù)。這有時是需要的,例如,當一個 generic method 不希望有參數(shù)時。思考 java.util.Collections.emptySet() 方法:它返回一個沒有元素的 set ,不象 Collections.singleton() 方法(你可以在上面的章節(jié)中找到),它沒有參數(shù)可是指定 set 的返回泛型參數(shù)。你需要在方法名稱前的尖括號中顯示的指定泛型參數(shù)。
    Java代碼 復制代碼
    1. Set<String> empty = Collections.<String>emptySet();  

    Type parameters cannot be used with an unqualified method name: they must follow a dot or come after the keyword new or before the keyword this or super used in a constructor.

    泛型參數(shù)不能和不合法的方法名連用:它們必須在一個"."后,或是緊跟在關鍵字 new 后,或者構造方法中在 this 或 super前。

    It turns out that if you assign the return value of Collections.emptySet() to a variable, as we did above the type inference mechanism is able to infer the type parameter based on the variable type. Although the explicit type parameter specification in the code above can be a helpful clarification, it is not necessary and the line could be rewritten as:

    其結果是如果你把 Collections.emptySet() 的返回值賦給變量,接著就會起動上面的類型推定機制斷定泛型參數(shù)所基于的變量類型。雖然上面的代碼顯式的指出泛型參數(shù),對識別很有幫助。但那是不一定需要的。這行代碼可以這樣改寫:
    Java代碼 復制代碼
    1. Set<String> empty = Collections.emptySet();  

    An explicit type parameter is necessary when you use the return value of the emptySet( ) method within a method invocation expression. For example, suppose you want to call a method named printWords( ) that expects a single argument of type Set<String>. If you want to pass an empty set to this method, you could use this code:

    顯式的泛型參數(shù)還是需要的,比如說你在一個方法的調用中,用了 emptySet()方法的返回值。例如,假定你想你調用的 printWords() 中有一個單獨的參數(shù),類型是 Set<String> 。如果你想傳遞一個空 set 給方法,你可以這樣寫代碼:
    Java代碼 復制代碼
    1. printWords(Collections.<String>emptySet());   
    2.    


    In this case, the explicit specification of the type parameter String is required.

    在這個例子中,顯示的說明泛型參數(shù) String 是需要的。

    4.1.4.5 Generic methods and arrays
    4.1.4.5 generic method 和數(shù)組

    Earlier in the chapter we saw that the compiler does not allow you to create an array whose type is parameterized. This is not, however, a restriction on all uses of arrays with generics. Consider the Util.fill() method defined above, for example. Its first argument and its return value are both of type T[]. The body of the method does not have to create an array whose element type is T, so the method is perfectly legal.

    本意早些時候,我們看到編譯器不允許創(chuàng)建一個參數(shù)化類型的數(shù)組。但是,這不是約束了數(shù)組的有關的用法。例如,考慮上面定義的 Util.fill() 的方法。它的第一個參數(shù)和返回值都是 T[] 類型的,方法體不一定創(chuàng)建一個有類型 T 元素的數(shù)組,因此這個方法是完全合法的。

    If you write a method that uses varargs (see Section 2.6.4 in Chapter 2) and a type variable, remember that invoking a varargs method performs an implicit array creation. Consider this method:

    如果你寫了一個用 varargs 的方法和一個泛型變量,記住調用一個 varargs 方法會執(zhí)行一個數(shù)組的隱式創(chuàng)建。考慮這個方法:
    Java代碼 復制代碼
    1. /** Return the largest of the specified values or null if there are none */  
    2. /** 返回指定值中最大的或是null(如果其中沒有最大的) */  
    3. public static <T extends Comparable<T>> T max(T... values) { ...  }   
    4.    


    You can invoke this method with parameters of type Integer because the compiler can insert the necessary array creation code for you when you call it. But you cannot call the method if you've cast the same arguments to be type Comparable<Integer> because it is not legal to create an array of type Comparable<Integer>[ ].

    你可以用類型為 Integer 調用這個方法,因為為了可以讓你調用編譯器可以根據(jù)需要動態(tài)創(chuàng)建一個數(shù)組。但你不能造型參數(shù)為 Comparable<integer>類型,因為創(chuàng)建類型為 Comparable<Ineteger> 的數(shù)組是非法的。

    4.1.4.6 Parameterized exceptions
    4.1.4.6 參數(shù)化異常

    Exceptions are thrown and caught at runtime, and there is no way for the compiler to perform type checking to ensure that an exception of unknown origin matches type parameters specified in a catch clause. For this reason, catch clauses may not include type variables or wildcards. Since it is not possible to catch an exception at runtime with compile-time type parameters intact, you are not allowed to make any subclass of THRowable generic. Parameterized exceptions are simply not allowed.

    異常是在運行期拋出和捕獲的,并且沒有辦法讓編譯器執(zhí)行類型檢查確保一個未知類型異常是否符合 catch 子句指定的泛型參數(shù)。為了這個理由, catch 子句不可以包含泛型變量或通配符。因為它不能在運行時捕獲一個編譯期原樣的泛型參數(shù)指定的異常,不允許使用 THRowable的泛型。參數(shù)化異常顯然不允許。

    You can, however, use a type variable in the throws clause of a method signature. Consider this code, for example:

    但你可以在 thows 子句里用泛型變量標記。例如,思考下面的代碼:
    Java代碼 復制代碼
    1. public interface Command<X extends Exception> {   
    2.     public void doit(String arg) throws X;   
    3. }   
    4.    


    This interface represents a "command": a block of code with a single string argument and no return value. The code may throw an exception represented by the type parameter X. Here is an example that uses a parameterization of this interface:

    這個接口表示了一個"命令":這個代碼塊有一單個的 String 泛型參數(shù)和無返回值。這段代碼可以拋出泛型參數(shù) X 表示的類型的異常。這有一個應用參數(shù)接口的例子:
    Java代碼 復制代碼
    1. Command<IOException> save = new Command<IOException>() {   
    2.     public void doit(String filename) throws IOException {   
    3.         PrintWriter out = new PrintWriter(new FileWriter(filename));   
    4.         out.println("hello world");   
    5.         out.close();   
    6.     }   
    7. };   
    8.     
    9. try { save.doit("/tmp/foo");  }   
    10. catch(IOException e) { System.out.println(e); }   
    11.    

    4.1.5. Generics Case Study: Comparable and Enum
    4.1.5. 泛型實例學習:Comarable 和 Enum

    The new generics features in Java 5.0 are used in the Java 5.0 APIs, most notably in java.util but also in java.lang, java.lang.reflect, and java.util.concurrent. These APIs were carefully created or reviewed by the inventors of generic types, and we can learn a lot about the good design of generic types and methods through the study of these APIs.

    Java 5.0 的這個泛型新特征被應用到了 Java 5.0 的 API 中,尤其是在 java.util 包中,但在包 java.lang,java.lang.reflect 和包java.util.cocurrent中也有。這些 API 被 Java 泛型的創(chuàng)造者們精心的用泛型重寫過了,我們可以通過學習這些 API ,從中學到很多有關 generic type  generic method的很好的設計思想。

    The generic types of java.util are relatively easy: for the most part they are collections classes, and type variables are used to represent the element type of the collection. Several important generic types in java.lang are more difficult. They are not collections, and it is not immediately apparent why they have been made generic. Studying these difficult generic types gives us a deeper understanding of how generics work and introduces some concepts that we have not yet covered in this chapter. Specifically, we'll examine the Comparable interface and the Enum class (the supertype of enumerated types, described later in this chapter) and will learn about an important but infrequently used feature of generics known as lower-bounded wildcards.

    包 java.util 的泛類型相對還是比較容易的:大多數(shù)是Collection的類,通常泛型變量用來表示Collection元素的類型。幾個重要的泛類型是在 java.lang 包中的,而且也比較難。他們不是Collection,也不是顯而易見的被泛化了。要研究這些比較難的泛類型,就要求我們深入理解泛型是怎么工作的,深入理解本章涉及到的概念。特別是,我們在驗證接口 Comparable 和類 Enum (它是 enumerated 類型的超型,也就是我們下一章要學習的) 將學到很重要但用的很少的著名的下界通配符。

    In Java 5.0, the Comparable interface has been made generic, with a type variable that specifies what a class is comparable to. Most classes that implement Comparable implement it on themselves. Consider Integer:

    在 Java 5.0 中,接口 Comparable 接口已經(jīng)被泛化,用泛型變量指定一個可比較的類。大多數(shù)類自己實現(xiàn) Comparable 。思考類型 Integer :
    Java代碼 復制代碼
    1. public final class Integer extends Number implements Comparable<Integer>   
    2.    


    The raw Comparable interface is problematic from a type-safety standpoint. It is possible to have two Comparable objects that cannot be meaningfully compared to each other. Prior to Java 5.0, the nongeneric Comparable interface was useful but not fully satisfactory. The generic version of this interface, however, captures exactly the information we want: it tells us that a type is comparable and tells us what we can compare it to.

    以類型安全的觀點看,原始的 Comparable 接口是有總是的。它可能有兩要比較的對象,但它們之間可能沒有有意義的比較。在 Java 5.0 之前,非泛型的 Comparable 接口是非常有用的,但不夠安全?,F(xiàn)在泛型版的這個接口,可以得到我們想要的精確信息:它告訴我們類型是 Comparable 的,可以進行比較。

    Now consider subclasses of comparable classes. Integer is final and cannot be subclassed, so let's look at java.math.BigInteger instead:

    現(xiàn)在思考 Comarable 的子類。 Integer 類型是 final 和不可子類化的,因此,我們用 java.math.BigInteger 替代一下:
    Java代碼 復制代碼
    1. public class BigInteger extends Number implements Comparable<BigInteger>   
    2.    


    If we implement a BiggerInteger subclass of BigInteger, it inherits the Comparable interface from its superclass. But note that it inherits Comparable<BigInteger> and not Comparable<BiggerInteger>. This means that BigInteger and BiggerInteger objects are mutually comparable, which is usually a good thing. BiggerInteger can override the compareTo( ) method of its superclass, but it is not allowed to implement a different parameterization of Comparable. That is, BiggerInteger cannot both extend BigInteger and implement Comparable<BiggerInteger>. (In general, a class is not allowed to implement two different parameterizations of the same interface: we cannot define a type that implements both Comparable<Integer> and Comparable<String>, for example.)

    如果我們實現(xiàn)了一個 BigInteger 的子類 BiggerInteger ,它從超類那里繼承了 Comparable 接口。但是注意了,它繼承的是 Comparable<BigInteger> 而不是 Comparable<BiggerInteger> 。這意味著 BigInteger 和 BiggerInteger 的對象是相互兼容的,這通常是個好事。BiggerInteger 能覆蓋超類的 compareTo() 方法,但是不能被參數(shù)化成 Comparable 以外的類型實例。那就是說 BiggerInteger 不能擴展自 BigInteger 實現(xiàn) Comparable<BiggerInteger> 。(通常,一個類不可以對同一接口進行不同的參數(shù)化:例如,我們不能定義一個類型實現(xiàn)接口 Comarable<integer> ,又實現(xiàn)接口 Comarable<String> 。)

    When you're working with comparable objects (as you do when writing sorting algorithms, for example), remember two things. First, it is not sufficient to use Comparable as a raw type: for type safety, you must also specify what it is comparable to. Second, types are not always comparable to themselves: sometimes they're comparable to one of their ancestors. To make this concrete, consider the java.util.Collections.max() method:

    當你應用 Comparable 的對象時(比如說你做排序算法時),記住兩件事。第一,用原始的 Comparable 類型是不夠的:為了類型安全你必須指定它比較的是什么。第二,類型總是不可以和自己比較:有時可能會和自己的祖先比較。為了證實這一點,思考 java.util.Collections.max() 方法:
    Java代碼 復制代碼
    1. public static <T extends Comparable<? super T>> T max(Collection<? extends T> c)   
    2.    


    This is a long, complex generic method signature. Let's walk through it:

    ·         The method has a type variable T with complicated bounds that we'll return to later.

    ·         The method returns a value of type T.

    ·         The name of the method is max( ).

    ·         The method's argument is a Collection. The element type of the collection is specified with a bounded wildcard. We don't know the exact type of the collection's elements, but we know that they have an upper bound of T. That is, we know that the elements of the collection are type T or a subclass of T. Any element of the collection could therefore be used as the return value of the method.

    這是一個比較長又復雜的泛型方法說明,讓我們一步一步來解讀它:

    這個方法有一個有復雜邊界的泛型變量 T (我們稍后再說)。
    這個方法返回值的類型是 T 。
    這個方法的名稱是 max() 。
    這個方法的參數(shù)是類型 Collection 的。Collection 的元素類型也使用定了邊界通配符。我們不知道 Collection 元素的確切類型,但是我們知道它們都有共同的上界類型 T 。就是說,我們知道元素類型是 T 或是其子類。因此可以返回任何是 Collection 類型的元素值。
    That much is relatively straightforward. We've seen upper-bounded wildcards elsewhere in this section. Now let's look again at the type variable declaration used by the max( ) method:

    這還是相對容易看明白的。這個章節(jié)我們已經(jīng)看過其他的上界通配符?,F(xiàn)在讓我們再這個泛型變量在 max() 方法中的聲明:
    Java代碼 復制代碼
    1. <T extends Comparable<? super T>>   
    2.    


    This says first that the type T must implement Comparable. (Generics syntax uses the keyword extends for all type variable bounds, whether classes or interfaces.) This is expected since the purpose of the method is to find the "maximum" object in a collection. But look at the parameterization of the Comparable interface. This is a wildcard, but it is bounded with the keyword super instead of the keyword extends. This is a lower-bounded wildcard. ? extends T is the familiar upper bound: it means T or a subclass. ? super T is less commonly used: it means T or a superclass.

    這就是說首先,類型 T 必須實現(xiàn) Coomparable 接口。(泛型語法在類型邊界中用關鍵字 extends ,它也用在類和接口中。)我們現(xiàn)在的意圖是方法能找出Collection中 "maximum" 的對象。但是我們看一下這個參數(shù)化的 Comarable 接口。這個通配符用的邊界關鍵字是 super 而不是 extends 。這是向下通配。?  extends  T 我們是非常熟悉的:這意味著 T 或是其他子類。? super T 用的較少,這個意思是 T 或是它的超類。

    To summarize, then, the type variable declaration states "T is a type that is comparable to itself or to some superclass of itself." The Collections.min() and Collections.binarySearch( ) methods have similar signatures.

    總結一下,那就是泛型變量聲明的是" T 是一個可以自己比較或是可以和自己超類比較的類型"。Collections.min() 和 Collections.binarySearch() 方法有著類似的說明。

    For other examples of lower-bounded wildcards (that have nothing to do with Comparable), consider the addAll(), copy( ), and fill() methods of Collections. Here is the signature for addAll():

    其他下界通配符的例子(Comparable沒做什么),考慮 Collections 的 addAll(),copy() 和 fill() 方法。這里是 addAll() 聲明:
    Java代碼 復制代碼
    1. public static <T> boolean addAll(Collection<? super T> c, T... a)   
    2.    


    This is a varargs method that accepts any number of arguments of type T and passes them as a T[ ] named a. It adds all the elements of a to the collection c. The element type of the collection is unknown but has a lower bound: the elements are all of type T or a superclass of T. Whatever the type is, we are assured that the elements of the array are instances of that type, and so it is always legal to add those array elements to the collection.

    這是一個 varargs 方法,能接受數(shù)目變化類型為 T 的參數(shù),然后解析它成一個類型為 T[] 的數(shù)組 a 。它把 a  中的所有元素增加到Collection c 中。Collection中元素的類型是不知道的,但是有一個最低邊界:所有元素的類型是 T 或是 T 的超類。不管類型是什么,我們都可以放心的是:數(shù)組元素都是這個類型的;因此它總是可以合法的被增加到 c 中。

    Recall from our earlier discussion of upper-bounded wildcards that if you have a collection whose element type is an upper-bounded wildcard, it is effectively read-only. Consider List<? extends Serializable>. We know that all elements are Serializable, so methods like get() return a value of type Serializable. The compiler won't let us call methods like add() because the actual element type of the list is unknown. You can't add arbitrary serializable objects to the list because their implementing class may not be of the correct type.

    回顧我們上面討論的上界通配符,如果我們有一個Collection,它的元素類型是上界通配符,這樣的元素是只讀的。思考 List<? extends Serializable>。我們知道所有元素是 Serializable 的,因此象方法 get() 返回值的類型是 Serializable 的。編譯器不讓我們調用 add() 方法,因為實際的 list 元素的類型是未知的。你不能為 list 增加任意的序列化對象,因為他們的類型可能是不正確的。

    Since upper-bounded wildcards result in read-only collections, you might expect lower-bounded wildcards to result in write-only collections. This isn't actually the case, however. Suppose we have a List<? super Integer>. The actual element type is unknown, but the only possibilities are Integer or its ancestors Number and Object. Whatever the actual type is, it is safe to add Integer objects (but not Number or Object objects) to the list. And, whatever the actual element type is, all elements of the list are instances of Object, so List methods like get( ) return Object in this case.

    因為上界通配符,Collection中的結果是只讀的,你可能希望下界通配符的結果是只可寫的。但實際上卻不是這樣的。假設我們有一個類型 List<? super Integer> 。實際元素的類型是未知的,但這僅可能是類型 Integer 或是其祖先類型和 Object 。無論實際類型是什么,list 增加一個類型為 Integer 的元素是安全的( 但不是 Number 或是 Object )。并且,無論實際的類型是什么,list 的所有元素都是 Object 的實例,因此 List 的方法象 get() 在這時返回一個 Object。

    Finally, let's turn our attention to the java.lang.Enum class. Enum serves as the supertype of all enumerated types (described later). It implements the Comparable interface but has a confusing generic signature:

    最后,讓我們再看一下 java.lang.Enum 類。Enum 是服務于所有 enumerated type(稍后討論) 類型的超型。它實現(xiàn)了 Comparable 接口,但是有著一個晦澀的聲明:

    public class Enum<E extends Enum<E>> implements Comparable<E>, Serializable


    At first glance, the declaration of the type variable E appears circular. Take a closer look though: what this signature really says is that Enum must be parameterized by a type that is itself an Enum. The reason for this seemingly circular type variable declaration becomes apparent if we look at the implements clause of the signature. As we've seen, Comparable classes are usually defined to be comparable to themselves. And subclasses of those classes are comparable to their superclass instead. Enum, on the other hand, implements the Comparable interface not for itself but for a subclass E of itself!

    第一眼看過去,這個泛型變量 E 的聲明顯然是循環(huán)。再仔細看:這個聲明說了明了什么呢? Enum 必須是被參數(shù)化成自己的類型。如果你看了 implements 部分,這顯示是看起來循環(huán)定義泛型變量的原因。我們知道, Comparable 的類通常被定義成可以和自己比較。他們的子類可以和他們的超類比較。從另一方面說,Enum 實現(xiàn)接口 Comparable 不是為自己,是為了它自己的子類 E 。

    另外給出PDF版
    修訂一次:改了一些校對疏忽的地方。

    posted on 2008-11-17 17:04 蘆葦 閱讀(692) 評論(0)  編輯  收藏 所屬分類: JAVA
    主站蜘蛛池模板: 免费一级毛suv好看的国产网站 | 免费无码又爽又刺激网站直播 | 亚洲欧洲一区二区三区| 精品国产亚洲男女在线线电影| 99久久国产免费-99久久国产免费 99久久国产免费中文无字幕 | 亚洲久热无码av中文字幕| 小说区亚洲自拍另类| 一级毛片在线完整免费观看| 大地资源网高清在线观看免费| 一级视频免费观看| 日韩人妻无码精品久久免费一| 一级毛片免费观看不收费| 无码国产精品一区二区免费模式| 国产成人1024精品免费| 99视频免费播放| 日本大片在线看黄a∨免费| 亚洲色大成网站WWW久久九九 | 国产高清免费在线| 国产亚洲一区二区三区在线不卡| 亚洲精品视频在线看| 久久精品国产亚洲av影院| 国产亚洲人成在线播放| 无码日韩精品一区二区三区免费| a级成人毛片免费图片| 日韩在线播放全免费| 亚洲Av无码国产情品久久 | 全黄a免费一级毛片人人爱| 亚洲精品乱码久久久久久久久久久久 | 99ri精品国产亚洲| 久久亚洲精品高潮综合色a片| 亚洲中文字幕乱码AV波多JI| 窝窝影视午夜看片免费| 曰批全过程免费视频播放网站| 久久99青青精品免费观看| 日韩中文字幕免费| 亚洲高清在线观看| 国产精品亚洲专区在线播放| 18禁止看的免费污网站| 亚洲欧洲日产国码高潮αv| 亚洲成人激情小说| 日本免费一区二区三区|