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方法传入了两个实际参数,其中as的数据类型是List , 而ao的数据类型是List ,与泛型方法签名进行对比:test(Collection a, Collection c),编译器无法正确识别T所代表的实际类型

优化上述代码,将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);
   }
}
发布了207 篇原创文章 · 获赞 124 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/dawei_yang000000/article/details/105333144
今日推荐