示例一:
最初学习泛型方法时,想到一个可以使用泛型方法的例子,这个例子可以在一定程度上说明泛型方法的定义和使用,但是后来发现这个例子如果用泛型方法来实现的话非常不恰当。
先将就着看一下这个例子,后面再说明一下为什么会不恰当。
有一个需求,定义一个方法,去掉一个已有数组(非int、byte等基本数据类型的数组)中的重复元素,该方法返回一个对应数据类型的新数组。
因为数组元素的数据类型太多了,可以考虑使用Object类型的数组;但是方法必须返回与原始数组中元素类型相同的新数组,这就要求必须能在方法中知道原始数组元素的数据类型,显然如果使用Object数组的话是无法知道具体的元素数据类型的,所以考虑使用泛型方法来实现。代码如下:
public static <T> T[] removeRepetitionGeneric(T[] srcArray){
ArrayList<T> tempList = new ArrayList<>();
for(T t : srcArray){
if(!tempList.contains(t))
tempList.add(t);
}
return (T[])tempList.toArray();
}
这个方法在编译时没有错误,但是有一个警告:
warning: [unchecked] unchecked cast
return (T[])tempList.toArray();
^
required: T[]
found: Object[]
这个警告有可能导致程序出现异常,也有可能不出现异常,这取决于你如何使用该方法的返回值。先看一个正常的调用:
public static void main(String[] args){
Integer[] intArray = new Integer[]{4, 2, 4, 6, 1, 2, 4, 7, 8};
String[] strArray = { "java", "c++", "ruby", "c#", "java", "c++" };
System.out.println(Arrays.toString(removeRepetitionGeneric(intArray)));
System.out.println(Arrays.toString(removeRepetitionGeneric(strArray)));
}
上面的对该方法的调用不会出现异常;但下面的调用方式会出现运行时异常:
public static void main(String[] args){
Integer[] intArray = new Integer[]{4, 2, 4, 6, 1, 2, 4, 7, 8};
intArray = removeRepetitionGeneric(intArray);
System.out.println(Arrays.toString(intArray));
}
异常信息如下:
Exception in thread "main" java.lang.ClassCastException:
[Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
对比2次调用,区别在于,第一次调用时,我们把方法的返回值直接传给了Arrays的toString方法,Arrays的toString方法有一个重载的toString(Object[] a)的形式,所以该方法的返回值无论是Object[]类型,还是Integer[]类型,都可以传给Arrays的toString方法;但是第二次调用时,我们把返回值赋给了一个Integer[]类型的变量,也就是这次赋值导致了异常。
虽然我们在该方法返回时,将Object[]强制类型转换成Integer[]类型,但是该方法返回的依然是Object[]类型的结果,这就是为什么第一次调用正常,而第二次调用异常的原因。