Java5之後還提供了對泛型方法的支持,假設需要實現這樣一個方法,該方法負責將一個Object數組的所有元素添加到一個Collection集合中
static void fromArrayToCollection(Object[] a, Collection<Object> c)
{
for(object o:a)
{
c.add(o);
}
}
然而如下代碼會報錯:
String [] strArr = {"aaa", "bbb"};
List<String> strList = new ArrayList<>();
// Collection<String>對象不能當成Collection<Object>使用,如下代碼會報錯,Collection<String>對象不是Collection<Object>的子類
fromArrayToCollection(strArr, strList)
使用通配符Collection<?>也是不可行的,因爲Java不允許把對象放進一個未知類型的集合中。
泛型方法
爲此Java5提供了泛型方法(Generic Method),所謂泛型方法,就是在聲明方法時定義一個或多個泛型形參
修飾符<T, S>返回值類型 方法名(形參列表)
{
// 方法體...
}
修改之前的方法fromArrayToCollection
static <T> void fromArrayToCollection (T[] a, Collection<T> c)
{
for (T o:a)
{
c.add(o);
}
}
import java.util.*;
public class GenericMethodTest
{
// 聲明一個泛型方法,該泛型方法中帶一個T泛型形參,
static <T> void fromArrayToCollection(T[] a, Collection<T> c)
{
for (T o : a)
{
c.add(o);
}
}
public static void main(String[] args)
{
var oa = new Object[100];
Collection<Object> co = new ArrayList<>();
// 下面代碼中T代表Object類型
fromArrayToCollection(oa, co);
var sa = new String[100];
Collection<String> cs = new ArrayList<>();
// 下面代碼中T代表String類型
fromArrayToCollection(sa, cs);
// 下面代碼中T代表Object類型
fromArrayToCollection(sa, co);
var ia = new Integer[100];
var fa = new Float[100];
var na = new Number[100];
Collection<Number> cn = new ArrayList<>();
// 下面代碼中T代表Number類型
fromArrayToCollection(ia, cn);
// 下面代碼中T代表Number類型
fromArrayToCollection(fa, cn);
// 下面代碼中T代表Number類型
fromArrayToCollection(na, cn);
// 下面代碼中T代表Object類型
fromArrayToCollection(na, co);
// 下面代碼中T代表String類型,但na是一個Number數組,
// 因爲Number既不是String類型,
// 也不是它的子類,所以出現編譯錯誤
// fromArrayToCollection(na, cs);
}
}
- 程序定義了一個泛型方法,該泛型方法中定義了一個T泛型行參,這個T類型就可以在該方法內當成普通類型使用,與接口、類聲明中定義的泛型不同的是,方法聲明中定義的泛型只能在該方法裏使用,而接口、類聲明中定義的泛型則可以在整個接口、類中使用
- 與類、接口中使用泛型參數不同的是,方法中的泛型參數無須顯示傳入實際類型參數,當程序調用fromArrayToCollection()方法時,無須在調用該方法前傳入String、Object等類型,但系統依然可以知道爲泛型實際傳入的類型,因爲編譯器根據實參推斷出泛型所代表的類型,並且往往直接推斷出最直接的類型
fromArrayToCollection(sa, cs);
cs 是一個Collection<String>類型,與方法定義時的fromArrayToCollection(T[] a, Collection<T>c)進行比較----只比較泛型參數,不難發現該T類型所代表的實際類型是String類型
fromArrayToCollection(ia, cn);
cn是Collection<Number>類型,與此方法的方法簽名進行比較----只比較泛型參數,不難發現該T類型代表了Number類型
定義一個test()方法,該方法用於將前一個集合裏的元素複製到下一個集合中,該方法中的兩個行參from、to的類型都是Collection,這要求調用該方法時的兩個集合實參中的泛型類型相同,否則編譯器無法準確的推斷出泛型方法中泛型行參的類型
import java.util.*;
public class ErrorTest
{
// 聲明一個泛型方法,該泛型方法中帶一個T泛型形參
static <T> void test(Collection<T> from, Collection<T> to)
{
for (var ele : from)
{
to.add(ele);
}
}
public static void main(String[] args)
{
List<Object> as = new ArrayList<>();
List<String> ao = new ArrayList<>();
// 下面代碼將產生編譯錯誤
test(as, ao);
}
}
優化上述代碼,將test()方法的前一個行參類型改爲Collection<? extends T>,這種採用類型通配符的表示方式,只要test()方法的前一個Collection集合裏的元素類型是後一個Collection集合裏元素類型的子類即可
import java.util.*;
public class RightTest
{
// 聲明一個泛型方法,該泛型方法中帶一個T形參
static <T> void test(Collection<? extends T> from, Collection<T> to)
{
for (var ele : from)
{
to.add(ele);
}
}
public static void main(String[] args)
{
List<Object> ao = new ArrayList<>();
List<String> as = new ArrayList<>();
// 下面代碼完全正常
test(as, ao);
}
}