Метод клонирования Java не работает

Я копирую текущее лучшее решение своей программы следующим образом:

public Object clone() 
{   
    MySolution copy = (MySolution)super.clone();
    copy.wtour =    (int[])this.wtour.clone();
    copy.w =        (int[][][][])this.w.clone();

    return copy;
}

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

Изменить: это часть оптимизатора поиска с ограничениями, который генерирует решения и сохраняет новые текущие лучшие решения (как здесь). Метод клонирования сохраняет туры по проблеме маршрутизации, где w [] [] [] [] является двоичной переменной решения и wtour является его копией, но состоит из номеров клиентов в последовательности посещения, то есть [0, 5, 3, 2, 1, 4].

Изменить: я изменил свою программу в соответствии с Робби Корнелиссеном следующим образом:

    public Object clone()   {   
        MySolution copy = (MySolution)super.clone();
        copy.w = copy2(w);
        return copy;
    } 

    public static int[][][][] copy2(int[][][][] source) {
    int[][][][] target = source.clone();

    for (int i = 0; i < source.length; i++) {
        target[i] = source[i].clone();

        for (int j = 0; j < source[i].length; j++) {
            target[i][j] = source[i][j].clone();

            for (int q = 0; q < source[i][j][q].length; q++) {
                target[i][j][q] = source[i][j][q].clone();

            }
        }
    }

    return target;
}

В результате я получаю клон следующего вида:

w[0][5][1][0]=1
w[4][2][2][0]=1
w[2][5][3][0]=1
w[5][0][4][0]=1
w[0][4][1][1]=1
w[6][1][2][1]=1
w[1][3][3][1]=1
w[3][0][4][1]=1

Проблема в том, что только первый элемент из этого принадлежит к самому лучшему решению (w [0] [5] [1] [0]). Почему другие не копируются?

РЕШЕНИЕ: я изменил свою программу как предоставленный ссылка предлагает следующее:

public Object clone()
{   
    MySolution copy = (MySolution)super.clone();
    copy.w = deepCopyOf(w);
    return copy;
}   // end clone

@SuppressWarnings("unchecked")
public static <T> T[] deepCopyOf(T[] array) {

    if (0 >= array.length) return array;

    return (T[]) deepCopyOf(
            array, 
            Array.newInstance(array[0].getClass(), array.length), 
            0);
}

private static Object deepCopyOf(Object array, Object copiedArray, int index) {

    if (index >= Array.getLength(array)) return copiedArray;

    Object element = Array.get(array, index);

    if (element.getClass().isArray()) {

        Array.set(copiedArray, index, deepCopyOf(
                element,
                Array.newInstance(
                        element.getClass().getComponentType(),
                        Array.getLength(element)),
                0));

    } else {

        Array.set(copiedArray, index, element);
    }

    return deepCopyOf(array, copiedArray, ++index);
}

person Hendrik    schedule 12.06.2015    source источник
comment
Не могли бы вы прояснить, в чем проблема при запуске вашей программы? Что вы ожидаете, и что происходит на самом деле? Какие признаки указывают на проблему?   -  person John D.    schedule 12.06.2015
comment
Можете ли вы предоставить подробную информацию о классе, который вы пытаетесь клонировать?   -  person Ediac    schedule 12.06.2015
comment
Также имейте в виду, что clone() по сути не работает, поэтому вы можете просто развернуть свое собственное решение для копирования.   -  person Kayaman    schedule 12.06.2015


Ответы (1)


Проблема в следующем:

  • Когда вы clone массив примитивов, объект массива и его значения клонируются.
  • Когда вы clone массив объектов, объект массива клонируется, но клонированный массив будет содержать ссылки на те же объекты, которые содержались в исходном массиве.

Что это значит для вашего случая?

  • Ваше значение wtour похоже на массив, содержащий примитив int, поэтому применяется первый из двух случаев, описанных выше. Т.е. как массив, так и его содержимое эффективно копируются.
  • Однако ваше значение w кажется многомерным массивом ints. На практике это означает, что на самом деле это массив, содержащий массив объектов, поэтому применим второй случай. Хотя ваш объект массива верхнего уровня копируется, скопированный массив содержит ссылки на те же объекты массива второго уровня, что и исходный массив.

Аналогичная проблема и возможные решения обсуждаются здесь.

Обновить

Как указано в комментариях, простая реализация может выглядеть так. Обратите внимание, что это полностью не проверено:

public static int[][][] copy(int[][][] source) {
    int[][][] target = source.clone();

    for (int i = 0; i < source.length; i++) {
        target[i] = source[i].clone();

        for (int j = 0; j < source[i].length; j++) {
            target[i][j] = source[i][j].clone();
        }
    }

    return target;
}
person Robby Cornelissen    schedule 12.06.2015
comment
Действительно, ваша ссылка относится к очень похожей проблеме. Придется ли мне создать новый метод deepCopy (), как предлагается там, или я могу просто изменить свой и выполнить итерацию по w [] [] [] [], чтобы сделать правильный клон o w [] [] [] []? - person Hendrik; 12.06.2015
comment
Если вы решили повторить итерацию, имейте в виду, что вам нужно повторить итерацию на 2 уровня в глубину. - person Robby Cornelissen; 12.06.2015
comment
Что вы имеете в виду под двумя уровнями? Сначала клонировать массив, а затем каждую позицию ИЛИ клонировать на 4 уровня в глубину его 4-мерного массива? - person Hendrik; 12.06.2015
comment
Я думал, что это было только 3-мерным, поэтому я имел в виду, что вам нужно перебирать не только 2-й уровень, но и 3-й уровень. - person Robby Cornelissen; 12.06.2015
comment
Не могли бы вы привести этому пример? Я пытаюсь это сделать, но у меня это не работает: - / - person Hendrik; 12.06.2015
comment
Я обновил свой ответ. - person Robby Cornelissen; 12.06.2015
comment
Спасибо, это очень ценно. Я тоже обновил свой пост. - person Hendrik; 12.06.2015