8.4 泛型方法

一、定义泛型方法

所谓泛型方法,就是在声明方法时定义一个多个泛型形参。泛型方法的语法格式:

修饰符 <T,S> 返回值类型 方法名(形参列表)
{
    ///    方法体
}

泛型形参声明以尖括号括起来,多个泛型形参之间以逗号(,)隔开,所有泛型形参声明方法在修饰符和方法返回值类型之间
问题:将一个Object数组的所有元素添加到一个Collection集合中。

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);


		//下面代码的T代表String类型
		var sa=new String[100];
		Collection<String> cs=new ArrayList<>();
		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);
	}
}
---------- 编译Java ----------
GenericMethodTest.java:44: 错误: 无法将类 GenericMethodTest中的方法 fromArrayToCollection应用到给定类型;
		fromArrayToCollection(na,cs);
		^
  需要: T[],Collection<T>
  找到: Number[],Collection<String>
  原因: 推论变量 T 具有不兼容的上限
    等式约束条件:String
    下限:Number
  其中, T是类型变量:
    T扩展已在方法 <T>fromArrayToCollection(T[],Collection<T>)中声明的Object
1 个错误

输出完成 (耗时 4 秒) - 正常终止

与类、接口中使用的泛型参数不同的是,方法中的泛型参数无需显式地传入实际类型参数,如上面程序所示,当程序中调用fromArrayToCollection()方法时,无需传入在调用该方法前传入String、Object等类型,但系统依然可以知道为泛型实际的类型,因为编译器根据实参推断出泛型所代表的类型,它通常推断出最直接的类型。例如,下面调用代码:

fromArrayToCollection(sa,cs);

cs是一个Collection类型,与方法定义时的fromArrayToCollection(T[] a,Collection c)进行比较——只比较泛型参数,不难发现T类型代表的实际类型是String类型。
对于如下调用代码

fromArrayToCollection(ai,cn);

cn是一个Collection类型,与方法定义时的fromArrayToCollection(T[] a,Collection c)进行比较——只比较泛型参数,不难发现T类型代表的实际类型是Number类型,Integer是Number的子类,子类类型变量可以自动转化为父类类型变量。

为了编译器能够正确推断出泛型方法中泛型的类型,不要制造迷惑!一旦系统迷惑,将出现编译错误:

import java.util.*;
public class ErrorTest 
{
	//声明一个泛型方法,该泛型中带有一个T泛型形参
	static <T> void test(Collection<T> from,Collection<T> to)
		//将集合from的元素添加到集合to中
	{
		for(var ele:from)
		{
			to.add(ele);
		}
	}
	public static void main(String[] args) 
	{
		//当两个集合元素都相同时,系统可以推断出正确泛型类型
		List<Integer> ic1=new ArrayList<>();
		ic1.add(1);
		ic1.add(2);
		ic1.add(3);
		List<Integer> ic2=new ArrayList<>();
		test(ic1,ic2);//此时test()方法的泛型类型为Integer
		System.out.println(ic2);//[1,2,3]

		//当两个集合元素不同时,系统将迷惑
		List<Object> as=new ArrayList<>();
		ic1.add(1);
		ic1.add(2);
		ic1.add(3);
		List<String> ao=new ArrayList<>();
		test(as,ao);//此时无法判断test()方法的泛型类型
		System.out.println(ao);
	}
}
---------- 编译Java ----------
ErrorTest.java:21: 错误: 无法将类 ErrorTest中的方法 test应用到给定类型;
		test(ic1,ic2);//此时test()方法的泛型类型为Integer
		^
  需要: Collection<T>,Collection<T>
  找到: List<Integer>,List<Number>
  原因: 推论变量T具有不兼容的等式约束条件Number,Integer
  其中, T是类型变量:
    T扩展已在方法 <T>test(Collection<T>,Collection<T>)中声明的Object
ErrorTest.java:30: 错误: 无法将类 ErrorTest中的方法 test应用到给定类型;
		test(as,ao);//此时test()方法的泛型类型为Integer
		^
  需要: Collection<T>,Collection<T>
  找到: List<Object>,List<String>
  原因: 推论变量T具有不兼容的等式约束条件String,Object
  其中, T是类型变量:
    T扩展已在方法 <T>test(Collection<T>,Collection<T>)中声明的Object
2 个错误

输出完成 (耗时 1 秒) - 正常终止

上面程序传入test()方法的两个实际参数,其中as的数据类型是List

原文地址:https://www.cnblogs.com/weststar/p/12601591.html