Java可变形参是jdk5.0新增特性,对形参列表最后一个元素是数组类型的增强,原因是可以容纳数组类型,也可以传入多个元素,自动打包这些元素被一个生成的数组引用。
语法:
public void fun(X x, Y y,...,T... args);
因为需要推断出这个可变形参到底哪些部分打包,所以必须放置末尾。
注意1:
public void fun(Object... obj);
//1.当我们想传入int数组时
fun(1,2,3,4);
//2.调用了Integer.valueOf(i)方法,自动装箱。
//3.当new int数组呢?
fun(new int[]{1,2,3});
//4.本身int[]就是一个引用数组类型,此时作为一个参数传递给了Object[]。
打印结果:class [Ljava.lang.Object;
//5.解决方法:new Integer[]{1,2,3};
这是因为自动装箱的实现机制:编译器知道将基本数据类型传递给了引用数据类型后,将调用valueOf(i)方法得到的返回值取代了之前的基本数据类型!
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
//可以debug跟踪调试,会发现自动装箱调用了该方法。
注意2:
为什么可以使用可变形参泛型数组赋值呢?
public staticT[] max (T... t) { System.out.println(t.getClass()); Object[] t2 = t; System.out.println(t2.getClass()); return t; } 打印: class [Ljava.lang.Integer; class [Ljava.lang.Integer;
首先类型擦除,肯定不能用泛型构造数组的。如:
T t = new T[2];
这是因为类型擦除后,构造的是Object[]数组,当然里面可以存储任意类型数据,但是数组本身也是类型!
Object[] obj = new Object[1]; obj[0] = "HelloWorld!"; String[] str = (String[])obj;
这样就会报ClassCastException!我们有时候想返回类型数组:
publicT[] fun(T t) { ... T[] ts = new T[3];//错误 return ts; } //根本不能转换!所以不允许new 泛型数组
那么泛型自动装箱呢?
肯定不是Object[]数组!
public staticT[] max (T... t) { System.out.println(t.getClass()); Object[] t2 = t; System.out.println(t2.getClass()); return t; } 打印: class [Ljava.lang.Integer; class [Ljava.lang.Integer; //而不是 [java.lang.Object; //读者自行查阅反射与泛型相关知识
想法1:利用反射实现泛型可变形参
想法2:利用函数式接口实现泛型可变形参
其根本原因是如何在堆空间开辟一个就是数组元素本身的类型的数组,而不是一个Object[]数组!



