Java中使用可变参数(Ellipsis)时如何正确传递数组?
我明白你遇到的问题了——当你把Motor3[]数组传递给泛型构造器的可变参数T... connections时,遍历得到的每个元素竟然是Motor3[]类型,而不是你期望的Motor3。这其实是Java泛型和可变参数交互时的一个常见陷阱,我来帮你拆解原因和解决方法:
问题根源
Java的可变参数T...在编译阶段会被转换成T[],但当你传递一个数组给泛型可变参数时,编译器的类型推断会出现歧义:它不确定你是想把数组里的每个元素作为可变参数的独立项传入,还是把整个数组当作可变参数的单个元素传入。
在你的代码里,编译器默认选择了后者——把Motor3[]数组当作单个T类型元素,所以T被推断为Motor3[],最终connections实际上是一个Motor3[][]数组(包含一个Motor3[]元素)。这就是为什么你遍历打印时,每个con的类型是Motor3[]。
三种解决方案
1. 直接传递多个元素而非数组
如果你不需要预先把Motor3实例存到数组里,可以直接把每个实例作为参数传入,这样编译器会自动推断T为Motor3,并把这些实例打包成Motor3[]:
robots[0] = new Robot(ROMS::hello, 5, new Motor3(), new Motor3());
2. 显式指定泛型类型
如果必须使用数组传递,你可以在创建Robot对象时显式指定泛型参数T的类型,告诉编译器你期望T是Motor3而不是Motor3[]:
robots[0] = new <Motor3>Robot(ROMS::hello, 5, ma1);
这样编译器会把传入的Motor3[]直接当作T[](也就是Motor3[])使用,遍历的时候每个元素就是Motor3实例了。
3. 修改构造器参数为数组类型
如果你希望构造器只接收数组而不是可变参数,可以把T...改成T[],这样参数类型明确,不会出现推断歧义:
// 修改后的构造器 public <T> Robot(Function<Robot, Integer> rom, double turnconstant, T[] connections) { for(T con : connections) { System.out.println(con.getClass().getCanonicalName() + " " + Motor3.class.getCanonicalName()); } } // 调用方式不变,此时T会被正确推断为Motor3 robots[0] = new Robot(ROMS::hello, 5, ma1);
验证效果
采用上述任意一种方案后,你遍历connections时打印的con.getClass().getCanonicalName()应该会和Motor3.class.getCanonicalName()一致,符合你的预期。
内容的提问来源于stack exchange,提问作者Jacob Hicks

