1. 程式人生 > 其它 >JAVA面向物件學習——java集合———泛型

JAVA面向物件學習——java集合———泛型

泛型入門

 

從Java 5以後,Java引入了“引數化型別(parameterized type)”的概念,允許程式在建立集合時指定集合元素的型別,如List<String>,這表明該List只能儲存字串型別的物件。

 

Java的引數化型別被稱為泛型(Generic)。

 

 

 

 

 

 

在Java 7以前,如果使用帶泛型的介面、類定義變數,那麼呼叫構造器建立物件時構造器的後面也必須帶泛型了。

 

例如如下兩條語句:

 

 

 

 

 

 

從Java 7開始,Java允許在構造器後不需要帶完整的泛型資訊,只要給出一對尖括號(<>)即可,Java可以推斷尖括號裡應該是什麼泛型資訊。

 

即上面兩條語句可以改寫為如下形式:

 

 

 

 

把兩個尖括號並排放在一起非常像一個菱形,這種語法也就被稱為“菱形”語法。

 

需要說明的是,當使用var宣告變數時,編譯器無法推斷泛型的型別。因此,若使用var宣告變數,程式無法使用“菱形”語法。

 

Java 9再次增強了“菱形”語法,它甚至允許在建立匿名內部類時使用菱形語法,Java可根據上下文來推斷匿名內部類中泛型的型別。

 

 

 

 

 

 

深入泛型


所謂泛型,就是允許在定義類、介面、方法時使用型別形參,這個型別形參(或叫泛型)將在宣告變數、建立物件、呼叫方法時動態地指定(即傳入實際的型別引數,也可稱為型別實參)。

 

 

Java 5改寫了集合框架中的全部介面和類,為這些介面、類增加了泛型支援,從而可以在宣告集合變數、建立集合物件時傳入型別實參,這就是在前面程式中看到的List<String>和ArrayList<String>兩種型別。

 

 

 

 

 

=============================================================

 

 

 

 

Java 泛型(generics)是 JDK 5 中引入的一個新特性, 泛型提供了編譯時型別安全檢測機制,該機制允許程式設計師在編譯時檢測到非法的型別。

 

泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數

 

假定我們有這樣一個需求:寫一個排序方法,能夠對整型陣列、字串陣列甚至其他任何型別的陣列進行排序,該如何實現?

答案是可以使用 Java 泛型

使用 Java 泛型的概念,我們可以寫一個泛型方法來對一個物件陣列排序。然後,呼叫該泛型方法來對整型陣列、浮點數陣列、字串陣列等進行排序。


 

泛型方法

 

你可以寫一個泛型方法,該方法在呼叫時可以接收不同型別的引數。根據傳遞給泛型方法的引數型別,編譯器適當地處理每一個方法呼叫。

 

下面是定義泛型方法的規則:

  • 所有泛型方法宣告都有一個型別引數宣告部分(由尖括號分隔),該型別引數宣告部分在方法返回型別之前(在下面例子中的 <E>)。
  • 每一個型別引數宣告部分包含一個或多個型別引數,引數間用逗號隔開。一個泛型引數,也被稱為一個型別變數,是用於指定一個泛型型別名稱的識別符號。
  • 型別引數能被用來宣告返回值型別,並且能作為泛型方法得到的實際引數型別的佔位符。
  • 泛型方法體的宣告和其他方法一樣。注意型別引數只能代表引用型型別,不能是原始型別(像 int、double、char 等)。

 

 

java 中泛型標記符:

  • E - Element (在集合中使用,因為集合中存放的是元素)
  • T - Type(Java 類)
  • K - Key(鍵)
  • V - Value(值)
  • N - Number(數值型別)
  •  - 表示不確定的 java 型別

 

 

 

 

=================================================================

 

 

 

=================================================================

 

 

 

 

定義泛型介面、類

 

 

 

// 定義Apple類時使用了泛型宣告
public class Apple<T>
{
	// 使用T型別定義例項變數
	private T info;
	public Apple(){}
	// 下面方法中使用T型別來定義構造器
	public Apple(T info)
	{
		this.info = info;
	}
	public void setInfo(T info)
	{
		this.info = info;
	}
	public T getInfo()
	{
		return this.info;
	}
	public static void main(String[] args)
	{
		// 由於傳給T形參的是String,所以構造器引數只能是String
		Apple<String> a1 = new Apple<>("蘋果");
		System.out.println(a1.getInfo());
		// 由於傳給T形參的是Double,所以構造器引數只能是Double或double
		Apple<Double> a2 = new Apple<>(5.67);
		System.out.println(a2.getInfo());
	}
}

  

 

注意:

 

當建立帶泛型宣告的自定義類,為該類定義構造器時,構造器名還是原來的類名,不要增加泛型宣告。

 

例如,為Apple<T>類定義構造器,其構造器名依然是Apple,而不是Apple<T>!呼叫該構造器時卻可以使用Apple<T>的形式,當然應該為T形參傳入實際的型別引數。

 

Java 7提供了“菱形”語法,允許省略<>中的型別實參。

 

 

 

===========================================================================

 

============================================================================

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

有界的型別引數:

 

 

可能有時候,你會想限制那些被允許傳遞到一個型別引數的型別種類範圍。

 

例如,一個運算元字的方法可能只希望接受Number或者Number子類的例項。這就是有界型別引數的目的。

 

要宣告一個有界的型別引數,首先列出型別引數的名稱,後跟extends關鍵字,最後緊跟它的上界。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

泛型類

 

泛型類的宣告和非泛型類的宣告類似,除了在類名後面添加了型別引數宣告部分。

 

和泛型方法一樣,泛型類的型別引數宣告部分也包含一個或多個型別引數,引數間用逗號隔開。

 

一個泛型引數,也被稱為一個型別變數,是用於指定一個泛型型別名稱的識別符號。因為他們接受一個或多個引數,這些類被稱為引數化的類或引數化的型別。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

解析: 

 

在 //1 處會出現錯誤,因為 getUperNumber() 方法中的引數已經限定了引數泛型上限為 Number,所以泛型為 String 是不在這個範圍之內,所以會報錯。

 

3、型別萬用字元下限通過形如 List<? super Number> 來定義,表示型別只能接受 Number 及其上層父類型別,如 Object 型別的例項。