Java —— 泛型方法、泛類的使用方法
泛型
泛型原本是一種機制允許程式設計師在編譯時檢測到非法的型別。他通過型別引數來實現程式碼複用以提高程式碼的編寫效率。
1. 泛型方法
泛型方法擁有以下幾點特徵:
1. 由 <E>
作為引數宣告部分,此部分要放在引數返回值之前,表明這是一個泛型方法
2. 泛型方法可以接受不同型別的引數,根據泛型方法的引數型別,編譯器適當處理每一個方法呼叫
以下就為一個簡單的泛型方法演示
public class GenericMethodTest {
/**
* 泛型方法 printArray
* @param inputArray
*/
public static <E> void printArray(E[] inputArray) {
for (E element : inputArray){
System.out.printf("%s", element);
System.out.printf(" ");
}
System.out.println();
}
public static void main(String[] args) {
// 創造不同型別陣列 Integer , Double 和 Character
Integer[] integers = {1,2,3,4,5,6};
Double[] doubles = {1.1,1.2,1.3,1.4,1.5};
Character[] characters = {'G','D','C','A'};
//輸出不同型別是陣列
System.out.println("輸出Interger型別的陣列");
printArray(integers);
System.out.println(" ");
System.out.println("輸出Double型別的陣列" );
printArray(doubles);
System.out.println(" ");
System.out.println("輸出Character型別的陣列");
printArray(characters);
System.out.println(" ");
}
}
我們通過定義<E>
作為宣告變數,這個宣告變數可以理解為Integer,Double 等引用型型別的大集合。
例如:當你傳入的型別為Integer時,這個<E>
就為Integer去計算printArray函式,自動替換函式中的E
。
當傳入的型別不同,<E>
就不同,這樣我們就可以通過不同的傳入型別去實現同一段程式碼的重複使用了,這樣做可以大大提高程式碼的可用性。
2. 帶限制類型的泛型方法
試想一下如下情況,當我需要比較3個變數的大小時,是不是就需要3個變數都為同一型別?不然就會出現難以比較的情況。所以我們需要用到如下定義方法:
<T extends Comparable<T>>
這種定義方式就可以實現3種變數都圈定為同一型別,以下為一個簡單的程式碼演示:
public class MaximumTest {
/**
* 第一個T 代表泛型
* 第二個T 代表與第一個 T 對比
* 第三個 T 代表返回值
*
* @param x
* @param y
* @param z
* @return
*/
public static <T extends Comparable<T>> T Maximum(T x,T y,T z){
T max = x;
/**
* compareTo()方法
* 如果指定的數與引數相等返回0。
* 如果指定的數小於引數返回 -1。
* 如果指定的數大於引數返回 1。
*/
if (y.compareTo(max) > 0) {
max = y;
}
if (z.compareTo(max) > 0) {
max = z;
}
return max;
}
public static void main(String[] args) {
//判斷三個整數之間的最大數
System.out.printf("%d, %d, %d 三個數最大的數字為%d\n\n",3,4,5,Maximum(3, 4, 5));
//判斷三個浮點數之間的最大值
System.out.printf("%.1f, %.1f, %.1f 三個數最大的數字為%.1f\n\n",1.1,1.2,1.3,Maximum(1.1,1.2,1.3));
//判斷三個字串的最大值
System.out.printf("%s, %s, %s 三個數最大的數字為%s\n\n","apple","pear","orange",Maximum("apple","pear","orange"));
}
}
這裡的Comparable 需要理解為一個介面,通過實現其內部的compareTo()方法來判斷每次輸入的值是否為同一型別,如果為不同型別就不能通過編譯。
3 .泛類
不僅方法內可以新增宣告變數,一個類也可以通過新增宣告變數成為一個泛類。因為他們接受一個或多個引數,這些類被稱為引數化的類或引數化的型別。
以下是一個簡單的泛類演示:
/**
*
* @author 72921
*
* 在類的後面加上<T>(型別引數宣告部分) 標誌即表示該類為泛類
* T 可以接受不同的型別及內容
*
* @param <T>
*/
public class Box<T> {
private T t;
public void add(T t){
this.t = t;
}
public T get(){
return t;
}
public static void main(String[] args) {
Box<Integer> intergerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
/**
* 為兩個不同的類插入不同的內容
*/
intergerBox.add(10086);
stringBox.add("這是一個測試內容");
/**
* 輸出結果
*/
System.out.println("intergerBox輸出內容: "+intergerBox.get());
System.out.println("stringBox輸出內容: "+stringBox.get());
}
}
我們通過<T>
宣告變數定義了一個Box泛類,通過實現2個帶不同傳入型別的泛類物件說明泛類的用途和使用。
Box<Integer> intergerBox = new Box<Integer>();
Integer就限定了該類為Integer型別,T就可以用Integer替代計算。
intergerBox.add(10086);
這樣插入是正確的,當你插入float 或者 String 型別的時候編譯將不通過。
4 .萬用字元
型別萬用字元一般是使用?代替具體的型別引數。例如 List<?>
在邏輯上是List<String>,List<Integer>
的實現父類。
以下是簡單的萬用字元演示:
import java.util.ArrayList;
import java.util.List;
public class GenericTest {
public static void main(String[] args) {
/**
* 型別萬用字元一般是使用?代替具體的型別引數。
* 例如 List<?> 在邏輯上是List<String>,List<Integer> 等所有List<具體型別實參>的父類。
*/
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number =new ArrayList<Number>();
name.add("這是一條測試資料");
age.add(15);
number.add(301);
/**
* 使用 getData 函式輸出
*/
getData(name);
getData(age);
getData(number);
/**
* 使用 getNumberData 函式輸出
* extends Number 限制了輸出僅可是 Number
*/
//getNumberData(name);
getNumberData(age);
getNumberData(number);
}
public static void getData(List<?> list) {
System.out.println("data:"+list.get(0));
}
public static void getNumberData(List<? extends Number> list){
System.out.println("data:"+list.get(0));
}
}
我們定義3個不同傳入型別的List,然後往裡新增三條不同型別的資料。通過getData函式輸出其內容。
getData的引數List<?> list
就匹配了所有的List<all>
,這樣你只需要編寫一個函式就可以把所有的List的內容都輸出出去。
同樣,我們也可以通過List<? extends Number>
的方式來限制我們想要輸出的資料是否同步。
演示中getNumberData如此定義就是萬用字元泛型值接受Number及其下層子類型別。所以不能輸出String型別的資料。