1. 程式人生 > >Java核心技術第12章(2)

Java核心技術第12章(2)

12.3    泛型方法

    前面介紹瞭如何定義一個泛型類,實際上,還可以定義一個帶有型別引數的簡單方法.
class ArrayAlg
{
    public static <T> T getMiddle(T...a)
    {
        return a[a.length / 2];
    }
}
    這個方法是在普通類中定義的,而不是在泛型類中定義的.然而,這是一個泛型方法,可以從尖括號和型別變數看出這一點.注意,型別變數放在修飾符(這裡是 public static)的後面,返回型別的前面.
    泛型方法可以定義在普通類中,也可以定義在泛型類中.
    當呼叫一個泛型方法時,在方法名前的尖括號中放入具體的型別:

String middle = ArrayAlg.<String>getMiddle("John", "Q.", "Public");
    在這種情況下,方法呼叫中可以省略<String>型別引數.編譯器有足夠的資訊能夠推斷出所呼叫的方法.它用names的型別(即String[])與泛型型別T[]進行匹配並推斷出T一定是String,也就是說,可以呼叫
String middle = ArrayAlg.getMiddle("John", "Q.", "Public");

12.4    型別變數的限定

    有時,類或方法需要對型別變數加以約束.下面是一個典型的例子.要計算陣列中的最小元素:
class ArrayAlg
{
    public static<T> T min(T[] a)   // almost correct
    {
        if (a == null || a.length == 0)
            return null;
        T smallest = a[0];
        for (int i = 1; i < a.length; i++)
        {
            if (smallest.compareTo(a[i])
                    smallest = a[i];
        }
        return smallest;
    }
}
    但是,這裡有一個問題,變數smallest型別為T,這意味著它可以是任何一個類的物件,怎樣才能保證T所屬的類有compareTo方法呢?
    解決這個問題的方案似乎將T限制為實現了Comparable介面(只含一個方法compareTo的標準介面)的類.可以通過對型別變數T設定限定實現這一點:
public static <T extends Comparable> T min(T[] a) ...
    實際上Comparable介面本身就是一個泛型型別.
    現在,泛型的min方法只能被實現了Comparable介面的類(如String,Date等)的陣列呼叫.由於Rectangle類沒有實現Comparable介面,所有呼叫min將會產生一個編譯錯誤.
    註釋
:在C++中不能對模板引數的型別加以限制.如果程式設計師用一個不適當的型別例項化一個模板,將會在模板程式碼中報告一個錯誤資訊.
    在此為什麼使用關鍵字 extends 而不是 implements?畢竟Comparable是一個介面.下面的符號:
<T extends BoundingType>
    表示T應該繫結型別的子型別(subtype),T和繫結型別可以是類,也可以是介面.選擇關鍵字 extends 的原因是更接近子類的概念.
    一個型別變數或萬用字元可以有多個限定,例如:
T extends Comparable & Serializable
    限定型別用"&"分隔,而逗號用來分隔型別變數.
    在Java的繼承中,可以根據需要擁有多個介面超型別,但限定中至多有一個類.如果用一個類作為限定,它必須是限定列表中的第一個.
    pair2/PairTest2.java如下所示:
package pair2;

import java.util.Calendar;
import java.util.GregorianCalendar;

public class PairTest2
{
    public static void main(String[] args)
    {
        GregorianCalendar[] birthdays =
        {
            new GregorianCalendar(1906, Calendar.DECEMBER, 9),
            new GregorianCalendar(1815, Calendar.DECEMBER, 10),
            new GregorianCalendar(1903, Calendar.DECEMBER, 3),
            new GregorianCalendar(1910, Calendar.JUNE, 22)
        };
        Pair<GregorianCalendar> mm = ArrayAlg.minmax(birthdays);
        System.out.println("min = " + mm.getFirst().getTime());
        System.out.println("max = " + mm.getSecond().getTime());
    }
}

class ArrayAlg
{
    /**
     * Gets the minimum and maximum of an array of objects of type T
     * @param a an array of strings
     * @return a pair with the min and max value, or null if a is null or empty
     */
    public static <T extends Comparable> Pair<T> minmax(T[] a)
    {
        if (a == null || a.length == 0)
            return null;
        T min = a[0];
        T max = a[0];
        for (T element : a)
        {
            if (min.compareTo(element) > 0) min = element;
            if (max.compareTo(element) < 0) max = element;
        }
        return new Pair<>(min, max);
    }
}
    執行結果如下所示: