Как сохранить изменения массива, сделанные внутри функции?

Мне нужно сделать класс для работы с массивами со статическими универсальными методами. Например, в этой функции мне нужно вставить один массив (arr2) внутрь другого (arr1) по некоторому индексу (месту).

public static<T> void paste(T[] arr1, int place, T[] arr2) {
        Object[] temp = new Object[arr1.length + arr2.length];
        System.arraycopy(arr1, 0, temp, 0, place);
        System.arraycopy(arr2, 0, temp, place, arr2.length);
        System.arraycopy(arr1, place, temp, place+arr2.length, arr1.length-place);

        arr1 = (T[])temp;
    }

Функция работает правильно, но я не вижу изменений в основной функции. Результат всегда остается в функции вставки. Что я могу сделать в этой ситуации?

public static void main(String[] args) {
        Integer arr[] = {1 ,2 ,3 ,4, 5};
        Integer arr2[] = {11 ,22 ,33 ,44, 55};

        paste(arr, 2, arr2);
        show(arr);

    }

person I. Bilous    schedule 13.09.2018    source источник
comment
stackoverflow .com/questions/40480/ . Вам нужно изменить arr1, а не заменить его. Или return ваши модификации.   -  person Roddy of the Frozen Peas    schedule 13.09.2018
comment
@RoddyoftheFrozenPeas, массив length нельзя изменить в Java.   -  person Alex Shesterov    schedule 14.09.2018
comment
Поздравляем? Почему ты говоришь мне это?   -  person Roddy of the Frozen Peas    schedule 14.09.2018


Ответы (2)


Вы не можете изменить длину существующего массива. Следовательно, метод paste должен возвращать новый массив:

public static<T> T[] paste(T[] arr1, int place, T[] arr2) {
    ...

    return temp;
}

Затем в методе main вы присваиваете возвращаемое значение новой переменной и используете ее:

T[] result = paste(arr, 2, arr2);
show(result);

Конечно, вы также можете присвоить возвращаемое значение существующей переменной, т.е.:

arr = paste(arr, 2, arr2);
show(arr);

Почему это не работает так, как вы пробовали:

Если вы переназначите arr1 в методе paste, это не повлияет на вызывающий метод. Это изменит только локальную переменную (фактически значение параметра) внутри метода. ссылка в вызывающем методе (main) не может быть изменена из другого метода.


Относительно создания универсального массива:

Вы можете создать массив «правильного» типа (вместо массива Objects), используя отражение:

T[] temp = (T[]) Array.newInstance(arr1.getClass().getComponentType(), arr1.length + arr2.length);

Обратите внимание, что вам по-прежнему требуется приведение, но тип массива во время выполнения будет таким же, как тип arr1.

person Alex Shesterov    schedule 13.09.2018
comment
Таким образом, я не могу использовать return temp, потому что мой метод возвращает T[ ] - person I. Bilous; 13.09.2018
comment
@I.Bilous — отредактировал вопрос, чтобы решить проблему с типом массива. - person Alex Shesterov; 14.09.2018
comment
Большое спасибо! Это решение! - person I. Bilous; 14.09.2018

При передаче arr1 вы передаете копию указателя массива. Внутри метода вы работаете с этой копией указателя , а не с исходным указателем, полученным из внешнего метода. Когда вы назначаете temp для arr1, вы назначаете его копии, а не оригиналу, оригинал все еще указывает на другой массив.

public static<T> T[] paste(T[] arr1, int place, T[] arr2) {
  // your code here
return temp;
}

Если вы не хотите менять сигнатуру метода, это правильно. Но если мы предполагаем, что по какой-то причине вы не хотите этого делать. Затем вам нужно изменить фактический массив, который передается в качестве аргумента. В вашем конкретном примере вы не можете этого сделать, потому что ни arr1, ни arr2 не имеют подходящего размера. Но это был бы путь к более процедурному типу решения.

Пример процедуры, которая изменяет свой аргумент:

public void mutationProcedure(int array[],int position, int changeToValue) {
    array[position] = changeToValue;
}

В этом коде, если мы вызовем его извне, значение массива будет изменено.

ОБНОВЛЕНИЕ: решение без необходимости явного приведения. Я считаю, что это лучшее решение.

public static<T> T[] paste(T[] arr1, int place, T[] arr2) {
        T[] temp = Arrays.copyOf(arr1, arr1.length + arr2.length);
        System.arraycopy(arr2, 0, temp, place, arr2.length);
        return temp;
}

Сначала мы создаем новый массив, начиная с arr1, и размер равен обоим массивам. Затем мы копируем второй массив с позиции конца массива1 в конец. Поскольку класс Arrays работает с дженериками, нам не нужно явно приводить типы.

person Alexander Petrov    schedule 13.09.2018
comment
Как я могу использовать return temp ? Мой метод возвращает T[ ] - person I. Bilous; 13.09.2018
comment
Если я использую (T[]) temp и arr = paste(arr, 2, arr2), у меня возникает ошибка: java.lang.Object; cannot be cast to java.lang.Integer - person I. Bilous; 14.09.2018
comment
@I.Bilous Я думаю, что это решение лучше. Он не требует явного приведения и хорошо сочетается с дженериками. - person Alexander Petrov; 14.09.2018