Почему изменение в копии Arraylist изменяет оригинал?

Я пытаюсь скопировать содержимое ArrayList в другой и изменить содержимое копии. Я не хочу, чтобы это было отражено в оригинале.

Я проверил SO и внес соответствующие изменения, все та же проблема. Кто-нибудь может помочь? Я делюсь кодом ниже:

private ArrayList<CustVoiceListObject> FilterApprovedWorkFromList() {

        ArrayList<CustVoiceListObject> arrayListCopy = new ArrayList<>(arrayListCustVoice);

            for(int i =0; i<arrayListCopy.get(position).getPackageArray().size();i++)
            {
                if(!arrayListCopy.get(position).getPackageArray().get(i).getPackageApproved().equals("Y"))
                {
                    arrayListCopy.get(position).getPackageArray().remove(i);
                    i--;
                }
            }
        return arrayListCopy;
    }

Во время отладки, когда он собирается вернуться, я проверяю исходный массив arrayListCustVoice, но он также изменен аналогично arrayListCopy

Что мне не хватает?

ОБНОВЛЕНИЕ [В соответствии с предложениями][Этот вопрос не дублируется!]

Это мой модифицированный код:

 private ArrayList<CustVoiceListObject> FilterApprovedWorkFromList() {

        ArrayList<CustVoiceListObject> arrayListCopy = (ArrayList<CustVoiceListObject>) arrayListCustVoice.clone();

            for(int i =0; i<arrayListCopy.get(position).getPackageArray().size();i++)
            {
                if(!arrayListCopy.get(position).getPackageArray().get(i).getPackageApproved().equals("Y"))
                {
                    arrayListCopy.get(position).getPackageArray().remove(i);
                    i--;
                }
            }
        return arrayListCopy;
    }

На самом деле я применил Cloneable к своему исходному классу, но все же столкнулся с той же проблемой.

Обновление 2 [Заключение исследования]

Я наткнулся на эту ссылку

В моем случае есть 2 класса. Второй является подмножеством первого. Вставка ниже:

public class CustVoiceListObject implements Cloneable {

    private String txtSource, txtCustComment, txtCustOk, txtRepeat;

    private int numberOfPackages, complaintSerial;

    private ArrayList<CustomerVoicePackageListObject> packageArray;

    private Double totalAmount;

   //getters & setters & constructors

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }


}

Класс 2:

public class CustomerVoicePackageListObject implements Cloneable {

    public String packageCategory;
    public String packageName;
    public String partUsageFlag;
    public String laborUsageFlag;
    public String status;
    public String isApproved;

 //getters & setters & constructors

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

.clone() должен ссылаться на clone() КЛАССА, а не где-либо еще. И если это правильно, это спровоцирует принятие мер по устранению исключения в соответствии с моей реализацией clone() в каждом отдельном классе.

Итак, вот что я сделал, изменил цикл for на это:

 private CustVoiceListObject FilterApprovedWorkFromList() {

//Observe the change here. It's no more ArrayList, it's Class type
        CustVoiceListObject arrayListCopy = null;
        try {
            arrayListCopy = (CustVoiceListObject) arrayListCustVoice.get(position).clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        for(int i =0; i<arrayListCopy.getPackageArray().size();i++)
            {
                if(!arrayListCopy.getPackageArray().get(i).getPackageApproved().equals("Y"))
                {
                    arrayListCopy.getPackageArray().remove(i); //this is ArrayList<ClassType>. Nested class objects.
                    arrayListCopy.setTxtCustOk("OKOK"); //within the class
                    i--;
                }
            }
        return arrayListCopy;
    }

В результате изменения в packageArray отразились как в (неудача), так и в НО изменения в txtCustOk в базовом классе, измененные в копии, а не в оригинале (успех). Значит проблема в клонировании с помощью ArrayList

Итак, глубокое клонирование требует соблюдения следующих правил:

1.Не нужно отдельно копировать примитивы.

2. Все классы-члены в исходном классе должны поддерживать клонирование, а метод клонирования исходного класса в контексте должен вызывать super.clone() для всех классов-членов.

3. Если какой-либо класс-член не поддерживает клонирование, то в методе клонирования необходимо создать новый экземпляр этого класса-члена и скопировать все его атрибуты один за другим в новый объект класса-члена. Этот новый объект класса-члена будет установлен в клонированном объекте.

Итак, моя цель — избавиться от ArrayList и перенести эти элементы в этот класс. Это болезненно. Ищем легкую альтернативу.


person Kṛṣṇa    schedule 17.06.2016    source источник
comment
замените эту строку и проверьте ArrayList‹CustVoiceListObject› arrayListCopy = new ArrayList‹›(arrayListCustVoice); by ArrayList‹CustVoiceListObject› arrayListCopy = arrayListCustVoice;   -  person Vickyexpert    schedule 17.06.2016
comment
Это была моя первая попытка. Не удалось.   -  person Kṛṣṇa    schedule 17.06.2016
comment
Я не считаю отнесение этого вопроса к категории повторяющихся, подходящих. Ни одно из этих решений здесь не работает.   -  person Kṛṣṇa    schedule 18.06.2016


Ответы (2)


Проблема в том, что ваши элементы исходного ArrayList являются ссылочными значениями, поэтому вы просто копируете ссылки на эти объекты, но не сами объекты (которые кажутся массивами другого типа).

Взгляните на этот вопрос, который, по сути, касается такой же проблемы.

person DAXaholic    schedule 17.06.2016
comment
Забыл упомянуть, что это связано с JAVA. Концепция наверняка та же. - person Kṛṣṇa; 17.06.2016
comment
Другими словами: один и тот же объект помещается в оба списка, и изменение этого объекта будет видно в обоих списках. Возможно, сам объект должен быть клонирован, или при изменении новый объект должен заменить исходный объект. - person Joop Eggen; 17.06.2016

Операция копирования копирует исходный список, но не элементы списка.

То есть, если у oldList были следующие Person объекты:

oldList: John, Jane, Jude, Joe

И вы скопировали oldList в newList:

oldList: John, Jane, Jude, Joe
newList: John, Jane, Jude, Joe

А затем удалил John из newList:

oldList: John, Jane, Jude, Joe
newList: Jane, Jude, Joe

вы можете видеть, что это два разных списка. Но вы не изменяете списки, вы изменяете объекты внутри списка. Если бы имя Joe было изменено на Jim, у вас было бы:

oldList: John, Jane, Jude, Jim
newList: Jane, Jude, Jim

Вы сделали только то, что называется «поверхностной» копией. Вы хотите сделать «глубокую» копию, как показано здесь< /а>.


Изменить (в вопросе "Обновление 2")

Боюсь, ваше исследование не зашло достаточно далеко. В вашем (новом) классе 1:

public class CustVoiceListObject implements Cloneable {

    // ints, Doubles, Strings

    private ArrayList<CustomerVoicePackageListObject> packageArray;

    //getters & setters & constructors

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

вы просто вернули super.clone(), позволив Java сделать всю работу за вас. Это в основном делает мелкую копию, которая вызывает все ваши проблемы! С тем же успехом вы могли бы и не создавать объект ICloneable. Что вы упустили, так это то, что ints, Doubles и даже Strings уже успешно копируются, поэтому вам не нужно их клонировать. Но ArrayLists не клонирует, поэтому вам нужно помочь ему:

@Override
protected Object clone() throws CloneNotSupportedException {
    // First copy the easy stuff
    CustomerVoiceListObject cvlo = (CustomerVoiceListObject)super.clone();

    cvlo.packageArray = new ArrayList<CustomerVoicePackageListObject>(packageArray.size()); // Make sure it's the right size

    for (CustomerVoicePackageListObject cvplo: packageArray) {
        cvlo.packageArray.add(cvplo.clone());
    } // for
    return cvlo;
} // clone()
person John Burger    schedule 17.06.2016
comment
Я сделал такой же вывод. У вас есть ссылка на Java? - person Kṛṣṇa; 17.06.2016
comment
Я обновил свой ответ другой ссылкой для Java, хотя для этого требуется, чтобы ваш класс реализовал интерфейс ICloneable - person John Burger; 17.06.2016
comment
Пожалуйста, проверьте обновление, которое я добавил, и дайте знать - person Kṛṣṇa; 18.06.2016
comment
@Krsna Я отредактировал свой ответ в ответ на ваши обновления - person John Burger; 18.06.2016
comment
Спасибо, я постараюсь сообщить, так как это было важно понять, хотя на данный момент я удалил эту концепцию, чтобы уложиться в срок. - person Kṛṣṇa; 20.06.2016
comment
clone() имеет защищенный доступ в java.lang.Object Появляется при последнем появлении clone() - cvplo.clone() - person Kṛṣṇa; 20.06.2016