Java 如何确定varargs数组的组件类型?
使用varargs时,如何确定结果数组的组件类型 例如,该程序是否保证打印Java 如何确定varargs数组的组件类型?,java,generics,variadic-functions,Java,Generics,Variadic Functions,使用varargs时,如何确定结果数组的组件类型 例如,该程序是否保证打印true,或者其行为在技术上未指定 public static void main(String[] args) { foo("", 0); } static <T> void foo(T... arr) { System.out.println(arr.getClass() == Serializable[].class); } publicstaticvoidmain(字符串[]arg
true
,或者其行为在技术上未指定
public static void main(String[] args) {
foo("", 0);
}
static <T> void foo(T... arr) {
System.out.println(arr.getClass() == Serializable[].class);
}
publicstaticvoidmain(字符串[]args){
foo(“,0);
}
静态无效foo(T…arr){
System.out.println(arr.getClass()==Serializable[].class);
}
我不是100%确定,但我认为这与varargs无关,更像是动态绑定、泛型和类型擦除
Java中的数组是协变的,但泛型不是。换句话说,字符串[]是对象[]的子类型,而堆栈不是堆栈的子类型
资料来源:
因此,为了回答您的问题,此行为是指定、记录和预期的
在《有效Java》一书中,Joshua Bloch这样解释:
数组在两个重要方面不同于泛型类型。首先,数组是协变的。这个听起来很吓人的词的意思很简单,如果Sub是Super的子类型,那么数组类型Sub[]就是Super[]的子类型。相比之下,泛型是不变的:对于任何两种不同的类型Type1和Type2,List既不是List的子类型,也不是List的超类型[JLS,4.10;Naftalin07,2.5]。您可能认为这意味着泛型是有缺陷的,但可以说是数组有缺陷
你可能会问我为什么要谈论数组?因为varargs最终会变成数组
在以前的版本中,一种接受任意数量值的方法要求您在调用该方法之前创建一个数组并将值放入数组中
在一个数组中必须传递多个参数仍然是事实,但varargs功能会自动并隐藏该过程
资料来源:
这个答案可能不是你想要的100%答案,但可能会有所帮助。一般来说,arr.getClass()将返回一些数组类(最普通的
对象[]。类
,但也可以是整数[]。类
,数字[]。类
,甚至是可序列化[]。类
——通常是所有元素中最具体的类型,但我不会指望它,请参见m-szalik答案)。如果要确保数组中包含的所有类都是可序列化的实例,则必须检查每个元素(顺便说一句,所提供的实现不支持null
值):
静态无效foo(T…arr){
系统输出打印LN(数据流(arr)
.filter(e->!Serializable.class.isInstance(e.getClass()))
.findFirst()
.orElse(null)=null;
}
您可能想看看:
顺便说一句,我同意福格蒂船长的意见:
我不是100%确定,但我认为这与varargs无关,更像是动态绑定、泛型和类型擦除
注意:
以下是foo
实现的一些示例:
foo(1,2)
将是Integer[]
foo(1,2.0)
将是Number[]
foo(“,1)
将是Serializable[]
foo(null,2)
将是Integer[]
foo(“,new Object())
将是Object[]
这不是关于varargs,而是关于泛型。
编译过程中会丢失通用信息。您的varargs参数由编译器转换为数组。所以JVM不决定类型,但编译器决定类型
您的代码被编译成字节码,如下所示:
public static void main(String[] args) {
foo(new Serializable[]{"", Integer.valueOf(0)});
}
决策的算法相当长,但你可以在这里阅读。
我运行了这段代码,输出告诉您没有保证(至少如果类在不同层次结构分支上有多个公共祖先)
老实说,我不知道这个魔术背后的原因,但我就是不能发表评论
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
interface A{}
interface B{}
class AB implements A, B {}
class BA implements A, B {}
public static void main (String[] args) throws java.lang.Exception
{
foo(new AB(), new BA());
foo2(new AB(), new BA());
}
static <T> void foo(T... arr) {
System.out.println(arr.getClass() == A[].class);
}
static <T> void foo2(T... arr) {
System.out.println(arr.getClass() == B[].class);
}
}
更奇怪的事情:
如果在接口A
之前声明了接口B
,则结果相反:
false
true
改变方法调用中参数的顺序、方法声明的顺序以及实现中接口的顺序对我来说是无效的(1.8.0_51)。我希望这里的答案是“所有类型推理规则在其难以理解的复杂性中,总是与我尝试过的每个编译器至少有一些不匹配。”可能吧:还有下面。
true
false
false
true