Как создать универсальный метод, объединяющий массивы любого типа?

#java #generics

Вопрос:

У меня есть метод, который берет два массива и объединяет их с элементами в естественном порядке. Мне было интересно, можно ли сделать его универсальным, чтобы он мог принимать массивы любого типа и объединять их в массив того же типа?

Прямо сейчас я могу построить только массив Object

 public static void main(String[] args) {

    Integer[] i1 = {1, 3, 5, 7, 9};
    Integer[] i2 = {2, 4, 6, 8, 10, 12, 14};

    String[] s1 = {"A", "C", "E", "G"};
    String[] s2 = {"B", "D", "F"};

    System.out.println(Arrays.toString(mergeAndSortArrays(i1, i2)));
    System.out.println(Arrays.toString(mergeAndSortArrays(s1, s2)));
}

public static<T extends Comparable<T>> Object[] mergeAndSortArrays(T[] a, T[] b) {
    final Object[] merged = new Object[a.length   b.length];

    int aPos = 0, bPos = 0, curIndex = -1;

    while (  curIndex < merged.length) {

        int comp = a[aPos].compareTo(b[bPos]);
        merged[curIndex] = (comp < 0) ? a[aPos  ] : b[bPos  ];

        if (aPos == a.length) {
            while (bPos < b.length) {
                merged[  curIndex] = b[bPos  ];
            }
            break;
        }

        if (bPos == b.length) {
            while (aPos < a.length) {
                merged[  curIndex] = a[aPos  ];
            }
            break;
        }
    }

    return merged;
}
 

Ответ №1:

Вы не можете создать массив универсального типа в Java, но вы можете использовать лямбду создателя:

 public static<T extends Comparable<T>> T[] mergeAndSortArrays(
    T[] a, 
    T[] b, 
    IntFunction<T[]> arrayCreator
) {
    final T[] merged = arrayCreator.apply(a.length   b.length);

    ...
}
 

и затем:

 mergeAndSortArrays(i1, i2, Integer[]::new)
mergeAndSortArrays(s1, s2, String[]::new)
 

Или, как вариант, у вас есть Class<T> itemClass параметр метода (вместо лямбды), а затем используйте (T[]) Array.newInstance(itemClass, a.length b.length) его для создания нового массива.

Если вы хотите избежать дополнительных аргументов метода (например, лямбда-код создателя или класс элемента), вы можете использовать отражение для получения типа элемента массива:

 final Class<?> itemClass = a.getClass().getComponentType();
final T[] merged = (T[]) Array.newInstance(itemClass, a.length   b.length);
 

И, конечно, вы также можете использовать для этого существующую библиотеку, например Apache Commons:

 final T[] merged = org.apache.commons.lang3.ArrayUtils.addAll(a, b);
// ...
 

Ответ №2:

Если вы создадите mergedArray из типа из a, он может выглядеть следующим образом.

 public static <T extends Comparable<T>> T[] mergeAndSortArrays(T[] a, T[] b) {
    final T[] merged = (T[])Array.newInstance(a.getClass().getComponentType(), a.length   b.length);