【java基礎(五十二)】泛型方法和類型變量的限定

泛型方法

前面已經介紹瞭如何定義一個泛型類。實際上,還可以定義一個帶有類型參數的簡單方法。

class ArrayAlg {
	public static <T> T getMiddle(T... a) {
		return a[a.length / 2];
	}
}

這個方法是在普通類中定義的,而不是在泛型類中定義的。然而,這是一個泛型方法,可以從尖括號和類型變量看出這一點。注意,類型變量放在修飾符的後面,返回類型的前面。

泛型方法可以定義在普通類中,也可以定義在泛型類中。

當調用一個泛型方法時,在方法名前的尖括號中放入具體的類型:

String middle = ArrayAlg.<String>getMiddle("John", "Q", "PUblic");

在這種情況下,方法調用中可以省略<String>類型參數。編譯器有足夠的信息能夠推斷出所調用的方法。它用names的類型與泛型類型進行匹配並推斷出T一定是String。也就是說,可以調用:

String middle = ArrayAlg.getMiddle("John", "Q", "PUblic");

幾乎在大多數情況下,對於泛型方法的類型引用沒有問題。偶爾,編譯器也會提示錯誤,此時需要解釋錯誤報告。如:

double middle = ArrayAlg.getMiddle(3.14, 1729, 0);

錯誤消息會以晦澀的方式指出(不同的編譯器給出的錯誤消息可能有所不同):解釋這句代碼有兩種方法,而且這兩種方法都是合法的。簡單地說,編譯器將會自動打包參數爲1個Double和2個Integer對象,而後尋找這些類的共同超類型。事實上,找到2個這樣的超類型:Number和Comparable接口,其本身也是一個泛型類型。在這種情況下,可以財局的補救措施是將所有的參數寫爲double值。

類型變量的限定

有時,類或方法需要對類型變量加以約束。下面是一個典型的例子。我們要計算數組中的最小元素:

class ArrayAlg {
	public static <T> T min(T[] a) {
		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]) > 0) smallest = a[i];

		return smallest;
	}
}

但是,這裏有一個問題。請看一下min方法的代碼內部。變量smallest類型爲T,這意味着它可以是任何一個類的對象。怎麼才能確信T所屬的類有compareTo方法呢?

解決這個問題的方案是將T限制爲實現了Comparable接口的類。可以通過對類型變量T設置限定(bound)實現這一點:

public static <T extends Comparable> T min(T[] a) ...

實際上Comparable接口本身就是一個泛型類型。目前,我們忽略其複雜性以及編譯器產生的警告。

現在,泛型的min方法只能被實現了Comparable接口的類(如String、LocalDate等)的數組調用。

或許你會感到奇怪,在此爲什麼使用關鍵字extends而不是implements?畢竟,Comparable是一個接口。

<T extends BoundingType>

表示T應該是綁定類型的子類型(subtype)。T和綁定類型可以是類,也可以是接口。選擇關鍵字extends的原因是更接近子類的概念,並且Java的設計者也不打算在語言中再添加一個新的關鍵字。

一個類型變量或通配符可以有多個限定,如:

T extends Comparable & Serializable

限定類型用“&”分割,而逗號用來分割類型變量。

在Java的繼承中,可以根據需要擁有多個接口超類型,但限定中至多有一個類。如果用一個類作爲限定,它必須是限定列表中的第一個。

實例

PairTest2.java

package cn.freedompc.pair2;

import java.time.LocalDate;

import cn.freedompc.pair.Pair;

public class PairTest2 {

	public static void main(String[] args) {
		LocalDate[] birthdays = {
				LocalDate.of(1906, 12, 9),
				LocalDate.of(1815, 12, 10),
				LocalDate.of(1903, 12, 3),
				LocalDate.of(1910, 6, 22),	
		};
		Pair<LocalDate> mm = ArrayAlg.minmax(birthdays);
		System.out.println("min = " + mm.getFirst());
		System.out.println("max = " + mm.getSecond());
	}
	
}

class ArrayAlg {
	
	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 (int i = 1; i < a.length; i++) {
			if (min.compareTo(a[i]) > 0) min = a[i];
			if (max.compareTo(a[i]) < 0) max = a[i];
		}
		return new Pair<>(min, max);
	}
	
}

結果

在這裏插入圖片描述

捐贈

若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章