Java面向對象系列[v1.0.0][泛型方法]

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);
   }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章