aio*_*obe 9 java types variadic-functions
如果我理解正确,Integer[]是一个子类型Object[].你可以这样做
Object[] objs = new Integer[] { 1, 2, 3 };
Run Code Online (Sandbox Code Playgroud)
在玩var-args时我意识到,似乎编译器"过度接近"数组类型没有明显的原因.
例如,下面的程序打印123 123.如果印刷它会不会有意义/更精确123 6?
class Test {
public static Object combine(Object... objs) {
if (objs instanceof Integer[]) {
int sum = 0;
for (Integer i : (Integer[]) objs)
sum += i;
return sum;
} else {
String concat = "";
for (Object o : objs)
concat += o;
return concat;
}
}
public static void main(String[] args) {
System.out.println(combine("1", "2", "3")); // prints 123
System.out.println(combine(1, 2, 3)); // prints 123
}
}
Run Code Online (Sandbox Code Playgroud)
我想我的问题可以概括为:如果JLS被定义为T[]作为参数传递,那么是否会出现任何矛盾/问题T,所有参数类型的最小上限是什么?
编辑:我意识到,在这种特殊情况下,我可能会重载该combine方法Integer[](ideone demo).尽管如此,仍然存在为什么选择这种设计的问题.
至于这个具体问题:
如果JLS被定义为传递T []作为参数,是否会出现任何矛盾/问题,其中T是所有参数类型的最小上界?
是的,因为数组不是只读的; 它是可写的:
package com.example.test;
import java.util.Arrays;
public class Varargs3 {
public static Object[] changeLastArgument(Object... objs) {
if (objs.length > 0)
objs[objs.length-1] = "Pow!";
return objs;
}
public static void main(String[] args) {
System.out.println(
Arrays.toString(changeLastArgument(1,2,3))
);
}
}
Run Code Online (Sandbox Code Playgroud)
打印
[1, 2, Pow!]
Run Code Online (Sandbox Code Playgroud)
如果JLS是按照你要求的方式定义的(例如foo(T... args),如果你调用,foo(a,b,c)则编译器构造一个类型为a,b,c的最小上限的数组),那么这种情况将允许运行时错误:调用changeLastArgument(1,2,3)将创建一个类型的数组Integer[],但该changeLastArgument()方法将尝试分配"Pow!"给最后一个元素,你会得到一个运行时错误.
声明changeLastArgument()是指定其输入类型,因此它应该能够假设其输入参数是真正的Object[]而不是子类型Object[],以便它可以安全地修改输入参数.(这类似于PECS原则 - 为了使a List<T>既安全可读又可写,你不能使用任何通配符,如List<? extends T>安全可读但不安全可写 - 或者List<? super T>- 它是安全可写的但是不安全可读.)