Java中是否可以使用数组的varargs?

Java中是否可以使用数组的varargs?,java,variadic-functions,Java,Variadic Functions,我试图实现一种方法来合并任意数量的数组 @SuppressWarnings("unchecked") public static <T> T[] merge(T[]... arrs) { int length = 0; for (T[] arr : arrs) { length += arr.length; } T[] merged = (T[]) new Object[length]; int destPos = 0;

我试图实现一种方法来合并任意数量的数组

@SuppressWarnings("unchecked")
public static <T> T[] merge(T[]... arrs) {
    int length = 0;
    for (T[] arr : arrs) {
        length += arr.length;
    }

    T[] merged = (T[]) new Object[length];
    int destPos = 0;
    for (T[] arr : arrs) {
        System.arraycopy(arr, 0, merged, destPos, arr.length);
        destPos += arr.length;
    }
    return merged;
}
虽然此代码已成功编译,但会引发异常:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
    at ntalbs.test.ArrayMerge.main(ArrayMerge.java:25)
    String[] a = { "a", "b", "c" };
    String[] b = { "e", "f" };
    String[] c = { "g", "h", "i" };

    String[] m = merge(String.class, a, b, c);

代码看起来似乎合理并且编译成功,但不起作用,并在运行时引发异常。你能解释一下为什么这个代码不起作用吗?我遗漏了什么?

问题与varargs无关

正如错误消息所说:您的方法创建并返回一个对象[],您正在将其强制转换为字符串[]。但是对象[]不是字符串[]。因此有例外


查看Collection的源代码及其T[]toArray方法,了解它如何基本上完成您尝试执行的操作:创建一个T[]类型的数组。

问题与varargs无关

正如错误消息所说:您的方法创建并返回一个对象[],您正在将其强制转换为字符串[]。但是对象[]不是字符串[]。因此有例外


查看Collection的源代码及其T[]toArray方法,了解它如何基本上完成您尝试执行的操作:创建T[]类型的数组。

您可以通过T的类创建数组。由于传入了对象,因此可以从其中一个对象获取类型。大概是这样的:

    String[] a = {"a", "b", "c"};
    String[] b = {"e", "f"};
    String[] c = {"g", "h", "i"};

    String[] m = merge(a,b,c);
Class<T> clazz = arrs[0].getClass();
T[] arr = (T[]) Array.newInstance(clazz.getComponentType(), <length of all passed arrays>);

然后只需填充数组。

您可以通过T的类创建一个数组。由于传入了对象,因此可以从其中一个对象获取类型。大概是这样的:

    String[] a = {"a", "b", "c"};
    String[] b = {"e", "f"};
    String[] c = {"g", "h", "i"};

    String[] m = merge(a,b,c);
Class<T> clazz = arrs[0].getClass();
T[] arr = (T[]) Array.newInstance(clazz.getComponentType(), <length of all passed arrays>);

然后填充数组。

您的问题不是因为varargs

是因为那条线

T[] merged = (T[]) new Object[length];
对象数组不能强制转换为字符串数组

使用

注:


正如@JB所指出的,只有当您尝试合并相同的数组类型时,这才有效。如果要合并不同的数组类型,则必须找到所有数组共有的超级类型,并使用它来代替arrs[0]。getClass。

您的问题不是因为varargs

是因为那条线

T[] merged = (T[]) new Object[length];
对象数组不能强制转换为字符串数组

使用

注:


正如@JB所指出的,只有当您尝试合并相同的数组类型时,这才有效。如果要合并不同的数组类型,则必须找到所有数组共有的超级类型,并使用该类型代替arrs[0]。getClass。

无法将对象[]强制转换为字符串[]。您需要创建正确运行时类型的实例。 为此,可以使用java.lang.reflect.ArraynewInstance方法。要获得正确的类型,可以按如下方式向merge方法添加类参数:

public static <T> T[] merge(final Class<T> arrayType, T[]... arrs) {
    int length = 0;
    for (T[] arr : arrs) {
        length += arr.length;
    }

    @SuppressWarnings("unchecked")
    T[] merged = (T[]) Array.newInstance(arrayType, length);
    int destPos = 0;
    for (T[] arr : arrs) {
        System.arraycopy(arr, 0, merged, destPos, arr.length);
        destPos += arr.length;
    }
    return merged;
}

不能将对象[]强制转换为字符串[]。您需要创建正确运行时类型的实例。 为此,可以使用java.lang.reflect.ArraynewInstance方法。要获得正确的类型,可以按如下方式向merge方法添加类参数:

public static <T> T[] merge(final Class<T> arrayType, T[]... arrs) {
    int length = 0;
    for (T[] arr : arrs) {
        length += arr.length;
    }

    @SuppressWarnings("unchecked")
    T[] merged = (T[]) Array.newInstance(arrayType, length);
    int destPos = 0;
    for (T[] arr : arrs) {
        System.arraycopy(arr, 0, merged, destPos, arr.length);
        destPos += arr.length;
    }
    return merged;
}
是的,varargs适用于所有Java类型。上述异常是由行T[]merged=T[]new Object[length];生成的;,和瓦拉格一点关系都没有

数组不是设计为通用的。我建议改为使用Collections框架

如果无法更改代码结构,请尝试以下类似操作:

@抑制警告未检查 公共静态T[]合并[]。。。阵列{ int fullSize=0; 对于T[]数组:数组{ fullSize+=数组长度; } List ConcatatedList=新的ArrayListfullSize; 对于T[]数组:数组{ concatenatedList.AddAllarray.asListarray; } 类targetType=类数组 .getClass.getComponentType.getComponentType ; 返回concatenatedList.toArray T[]Array.newInstancetargetType,concatenatedList.size ; } 是的,varargs适用于所有Java类型。上述异常是由行T[]merged=T[]new Object[length];生成的;,和瓦拉格一点关系都没有

数组不是设计为通用的。我建议改为使用Collections框架

如果无法更改代码结构,请尝试以下类似操作:

@抑制警告未检查 公共静态T[]合并[]。。。阵列{ int fullSize=0; 对于T[]数组:数组{ fullSize+=数组长度; } List ConcatatedList=新的ArrayListfullSize; 对于T[]数组:数组{ concatenatedList.AddAllarray.asListarray; } 类targetType=类数组 .getClass.getComponentType.getComponentType ; 返回concatenatedList.toArray T[]Array.newInstancetargetType,concatenatedList.size ; } 我认为问题是T[]合并=T[]新对象[长度];不是数组varargs。您正在创建一个无法转换为字符串[]的新对象[]。我认为问题在于T[]合并=T[]新对象[length];不是数组varargs。您正在创建一个不能转换为字符串[]的新对象[]。对于newInstance方法,它应该是clazz.getComponentType。否则您将得到一个数组类型String[],而不是T中的String。一个小的修正,它应该是clazz.getComponentType
温斯顿方法。否则,您将得到一个数组类型String[],而不是T中的字符串。只有当所有输入数组都是相同类型时,这才有效。如果合并字符串[]和对象[],它将尝试创建一个字符串数组来容纳对象。谢谢@JBNizet。。。请注意指定。@jbnizett根据合并方法的签名,它们必须是相同的类型。请使用Classarrs.getClass.getComponentType.getComponentType来支持空参数列表。@DávidHorváth:另外,当参数是不同的数组类型时,它也支持,因为ARR被保证属于一个类,而这个类是所有ARR的超类型。只有当所有输入数组都是同一类型时,这才有效。如果合并字符串[]和对象[],它将尝试创建一个字符串数组来容纳对象。谢谢@JBNizet。。。请注意指定。@jbnizett根据合并方法的签名,它们必须是相同的类型。请使用Classarrs.getClass.getComponentType.getComponentType来支持空参数列表。@DávidHorváth:另外,当参数是不同的数组类型时,它也支持,因为arrs被保证是一个类,这个类是所有arrs的超类型。