使用varargs时,结果数组的组件类型是如何确定的?
例如,该程序是否保证打印true
或其技术上未指定的行为?
public static void main(String[] args) {
foo("", 0);
}
static <T> void foo(T... arr) {
System.out.println(arr.getClass() == Serializable[].class);
}
答案 0 :(得分:3)
我运行了这段代码,输出告诉你没有保证(至少如果类在不同的层次结构分支上有多个共同的祖先)
老实说,我不知道这种魔法背后的原因,但我不能将其作为评论发布
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);
}
}
<强>输出强>
true
false
更奇怪的事情:
如果在interface B
之前宣布interface A
,结果则相反:
false
true
在implements
块中更改方法调用,方法声明顺序和接口顺序中的参数顺序对我没有影响(1.8.0_51)。
答案 1 :(得分:2)
这个答案可能不是你要找的答案的100%,但也许有帮助。通常,arr.getClass()将返回一些数组类(最常见的Object[].class
,但也可能是Integer[].class
,Number[].class
,甚至是Serializable[].class
- 通常是最具体的所有元素的类型,但我不指望它看到m-szalik答案)。如果要确保数组中包含的所有类都是Serializable
的实例,则必须检查每个元素(顺便说一句。所呈现的实现不支持null
值):
static <T> void foo(T... arr) {
System.out.println(Stream.of(arr)
.filter(e -> !Serializable.class.isInstance(e.getClass()))
.findFirst()
.orElse(null) == null);
}
您可能需要查看:
顺便说一下。我同意Fogetti上尉的意见:
好吧,我对此并不是100%肯定,但我认为这与varargs无关,更像是动态绑定,泛型和类型擦除。
注意强>:
您的foo
实施的一些示例:
foo(1, 2)
将为Integer[].class
foo(1, 2.0)
将为Number[].class
foo ("", 1)
将为Serializable[].class
foo(null, 2)
将为Integer[].class
foo("", new Object())
将为Object[].class
答案 2 :(得分:1)
好吧,我对此并不是100%肯定,但我认为这与varargs无关,更像是动态绑定,泛型和类型擦除。
&#34; Java中的数组是协变的,但泛型不是。换句话说,String []是Object []的子类型,但Stack不是Stack的子类型。&#34;
来源: http://algs4.cs.princeton.edu/13stacks/
因此,为了回答您的问题,此行为已指定记录并预期。
在书中:&#39; Effective Java&#39;约书亚布洛赫解释如下:
阵列在两个重要方面与通用类型不同。首先,数组是协变的。这个可怕的单词意味着如果Sub是Super的子类型,那么数组类型Sub []是Super []的子类型。相反,泛型是不变的:对于任何两种不同类型Type1和Type2,List&lt; Type1&gt;既不是List&lt; Type2&gt;的子类型也不是超类型。 [JLS,4.10; Naftalin07,2.5]。您可能认为这意味着泛型有缺陷,但可以说它是缺陷的数组。
为什么我要谈论你可能会问的阵列?好吧,因为varargs最终将成为数组。
&#34;在以前的版本中,采用任意数量值的方法需要您创建数组并在调用方法之前将值放入数组中。&#34;
&#34;必须在数组中传递多个参数,但varargs功能会自动化并隐藏进程。&#34;
来源: https://docs.oracle.com/javase/8/docs/technotes/guides/language/varargs.html
答案 3 :(得分:1)
这不是关于varargs而是关于泛型的更多信息 编译期间遗失了通用信息。您的varargs参数由编译器转换为数组。因此JVM不会决定类型,但编译器会这样做。
您的代码将编译为字节码,如下所示:
public static void main(String[] args) {
foo(new Serializable[]{"", Integer.valueOf(0)});
}
决策算法很长,但你可以在这里阅读。 https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html