繁体   English   中英

Java中可能存在数组的可变参数吗?

[英]Is varargs of array possible in Java?

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

@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;
}

它编译,看起来没有问题。 然后我测试了这种方法:

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

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

尽管此代码已成功编译,但会引发异常:

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)

代码看起来合理且编译成功,但不起作用,并在运行时引发异常。 您能解释一下为什么此代码不起作用吗? 我想念什么?

这个问题与varargs无关。

如错误消息所述:您的方法创建并返回一个Object[] ,并将其强制转换为String[] 但是Object[]不是String[] 因此,例外。

查看Collection的源代码(及其T[] toArray()方法),以了解它基本上可以完成您想做的事情:创建一个T[]类型的数组。

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

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];

Object数组不能转换为String数组。

采用,

T[] merged = (T[])java.lang.reflect.Array.newInstance(
                            arrs[0].getClass().getComponentType(), length);

注意:

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

您不能将Object []转换为String []。 您需要创建正确的运行时类型的实例。 为此,可以使用java.lang.reflect.Array#newInstance方法。 要获得正确的类型,可以按如下所示将类参数添加到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;
}

这可以在没有运行时异常的情况下执行:

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

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

是的varargs适用于每种Java类型。 上面的异常是由行T[] merged = (T[]) new Object[length]; varargs无关。

数组不是通用的。 我建议改用Collections框架。

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

@SuppressWarnings("unchecked")
public static <T> T[] merge(T[]... arrays) {
    int fullSize = 0;
    for (T[] array: arrays) {
        fullSize += array.length;
    }
    List<T> concatenatedList = new ArrayList<T>(fullSize);
    for (T[] array: arrays) {
        concatenatedList.addAll(Arrays.asList(array));
    }
    Class<T> targetType = (Class<T>)arrays
        .getClass().getComponentType().getComponentType()
    ;
    return concatenatedList.toArray(
        (T[])Array.newInstance(targetType, concatenatedList.size())
    );
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM