簡體   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