一、定义泛型方法
所谓泛型方法,就是在声明方法时定义一个多个泛型形参。泛型方法的语法格式:
修饰符 <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(ai,cn);
cn是一个Collection
为了编译器能够正确推断出泛型方法中泛型的类型,不要制造迷惑!一旦系统迷惑,将出现编译错误:
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