Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Копирование ArrayList


Автор: Reptor 1.7.2008, 16:33
Проблема вот в чём:

есть какойто список private 

Код

ArrayList<X> list       = new ArrayList<X>();


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

Делаю так и всеровно не выходит. Меняю старый, меняется и новый и наоборот

Код

this.list        = new ArrayList<X>(list);


Как это побороть?

Автор: LSD 1.7.2008, 16:37
clone()
(но объекты в новом листе будут те же самые)

Автор: Reptor 1.7.2008, 16:53


this.list = ( ArrayList<X>)list.clone();

не помогло. Всеровно если менять объекты одного листа то в 2-ом они тоже меняются, ну и наоборот

Автор: cube 1.7.2008, 17:18
Цитата(Reptor @ 1.7.2008,  16:53)
this.list = ( ArrayList<X>)list.clone();

не помогло. Всеровно если менять объекты одного листа то в 2-ом они тоже меняются, ну и наоборот

тогда ты должен у каждого объекта Х в ArrayList'e использовать clone()

Автор: Reptor 1.7.2008, 17:23
так что выходит надо итератором проходить по листу и делать клоне каждого объекта а потом this.list.add( Object.clone() ) ?? 

мне кажется что такое копирование больших листов повешает всё приложение

Автор: Orange 1.7.2008, 18:13
а Collections.copy(list1, list2) не подойдёт?

(ну или делай свою реализацию cloneable)

Автор: Reptor 1.7.2008, 18:16
Orange, не знаю подойдёт или нет... не пробовал.. я так понимаю это с common-collections.. надо посмотреть как там реализовано..

Автор: Orange 1.7.2008, 18:21
Цитата(Reptor @ 1.7.2008,  18:16)
Orange, не знаю подойдёт или нет... я так понимаю это с common-collections.. надо посмотреть как там реализовано..

И да, у Эккеля было по поводу глубокого клонирования достаточно подробно описанно

Автор: Reptor 1.7.2008, 18:26
   
у меня при таком подходе ошибка

    
Код

    Collections.copy(this.list, list);


Exception occurred during event dispatching:
java.lang.IndexOutOfBoundsException: Source does not fit in dest

Автор: ivg 1.7.2008, 19:10
Цитата(Reptor @  1.7.2008,  19:33 Найти цитируемый пост)
Делаю так и всеровно не выходит. Меняю старый, меняется и новый и наоборот

А покажите как вы это делаете?

Автор: powerOn 1.7.2008, 22:02
Цитата(Reptor @  1.7.2008,  19:26 Найти цитируемый пост)
Exception occurred during event dispatching:
java.lang.IndexOutOfBoundsException: Source does not fit in dest 


если посмотреть в исходники Collections.sort, то можно узнать много интересного:

Код

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
        int srcSize = src.size();
        if (srcSize > dest.size())
            throw new IndexOutOfBoundsException("Source does not fit in dest");

        if (srcSize < COPY_THRESHOLD ||
            (src instanceof RandomAccess && dest instanceof RandomAccess)) {
            for (int i=0; i<srcSize; i++)
                dest.set(i, src.get(i));
        } else {
            ListIterator<? super T> di=dest.listIterator();
        ListIterator<? extends T> si=src.listIterator();
            for (int i=0; i<srcSize; i++) {
                di.next();
                di.set(si.next());
            }
        }
    }


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

Автор: Platon 1.7.2008, 22:23
На сколько могу судить по исходному коду Collections.copy тоже не подходит, он копирует только ссылки.

Автор: powerOn 1.7.2008, 23:15
Цитата(Platon @  1.7.2008,  23:23 Найти цитируемый пост)
он копирует только ссылки. 

это точно.

Автор: Kangaroo 2.7.2008, 00:14
Цитата(powerOn @  1.7.2008,  22:02 Найти цитируемый пост)
Но, честно говоря, зачем такое условие нужно я плохо себе представляю.

Наверное, чтобы максимально оптимизировать следующий за этой проверкой код.

Автор: COVD 2.7.2008, 01:52
Цитата

так что выходит надо итератором проходить по листу и делать клоне каждого объекта а потом this.list.add( Object.clone() ) ?? 


конечно. Или вы это вручную должны сделать (если это реально нужно и время не ждет), или найдете готовый библиотечный класс, где то же самое уже реализовано. Но никакого чуда там не будет.

Цитата

мне кажется что такое копирование больших листов повешает всё приложение


Есть программистская заповедь: "Не плодите сущности".  Из которой следует, что вам лучше поискать другое решение. 

Автор: LSD 2.7.2008, 10:05
Нет ни одного готового класса который мог бы осуществлять глубокое клонирование, потому что у Object метод clone() не public.

Так что или писать такое дело самому (с учетом того, что храниться в List) или сделать клонирование через сериализацию (объекты естественно должны быть сериализуемы).

Автор: Reptor 2.7.2008, 10:54
ехххх, да незадачка. 


мне удивительно почему не помагает   

Код

class X{
.....
}

class X2{

   private ArrayList<X> list   = new ArrayList<X>();
   
   public X2(ArrayList<X> list){
               this.list =  new ArrayList<X>(list)
   }
}



вроде ж как через new..


Автор: LSD 2.7.2008, 11:17
new создает новый ArrayList и копирует туда ссылки на объекты из исходной коллекции.

Автор: Reptor 2.7.2008, 11:48
попробую конечно через итераторы но думаю что ничего хорошего из этого не выйдет. 


LSD,  а как это через сериализацию?

Добавлено @ 11:55
ого так это ж ещё надо будет создавать каждый объект что в листе заново.... ведь если их просто переписать всеровно ссылки та останутся на старые...

не это не реально, это все переменные объекта надо будет достать и заново записать в новый объект, мало того что объектов не мало в листе так ещё и у объекта много всего...

Автор: Platon 2.7.2008, 13:02
Reptor, ну, а что сделать? Ты такие условия ставишь. Или смирись, или ищи как обойтись только ссылками на объекты.

Автор: Reptor 2.7.2008, 13:11
Platon,  ну а как обойтись ссылками... не как не выйдет так как они то должны быть независимы а так меняеш один меняется 2-ой...   smile 

Автор: LSD 2.7.2008, 13:54
Цитата(Reptor @  2.7.2008,  12:48 Найти цитируемый пост)
LSD,  а как это через сериализацию?

Да практически как гланды удалять через ж smile 
Код

  public static Object serialClone(Serializable s)
  {
    try
    {
      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
      ObjectOutputStream objectOut = new ObjectOutputStream(byteOut);
      objectOut.writeObject(s);
      objectOut.close();

      ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
      ObjectInputStream objectIn = new ObjectInputStream(byteIn);
      Object copy = objectIn.readObject();
      objectIn.close();
      return copy;
    }
    catch(IOException e)
    {
      return null;// mustn't happend
    }
    catch(ClassNotFoundException e)
    {
      return null;// mustn't happend
    }
  }

  public static void main(String[] args) throws Exception
  {
    StringBuilder buffer = new StringBuilder("aaa");
    ArrayList<StringBuilder> list  = new ArrayList<StringBuilder>();
    list.add(buffer);

    ArrayList<StringBuilder> copy1  = (ArrayList<StringBuilder>) list.clone();
    ArrayList<StringBuilder> copy2  = (ArrayList<StringBuilder>) serialClone(list);

    System.out.println("list  = " + list);
    System.out.println("copy1 = " + copy1);
    System.out.println("copy2 = " + copy2);

    System.out.println("Changing...");
    buffer.append("bbbb");
    list.add(new StringBuilder("zzz"));

    System.out.println("list  = " + list);
    System.out.println("copy1 = " + copy1);
    System.out.println("copy2 = " + copy2);
  }

только учти, что это штука не быстрая и глубокое клонирование будет работать быстрее.

Автор: Reptor 2.7.2008, 14:05
Цитата

что это штука не быстрая и глубокое клонирование будет работать быстрее


я не совсем понимаю что имеется в виду под глубоким копированием? почему глубоким?

Автор: dorogoyIV 2.7.2008, 14:41
Цитата(Reptor @  2.7.2008,  14:05 Найти цитируемый пост)
я не совсем понимаю что имеется в виду под глубоким копированием? почему глубоким?

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

 smile  тоже наверное не очень понятно пояснил  smile 

Автор: Reptor 2.7.2008, 15:38
dorogoyIV,  всё я понял..  smile  

всем огромное спасибо... 

надо будет попробовать сделать 2 варианта.

Автор: Reptor 3.7.2008, 11:01
LSD,  смотри я немножко поменял то что ты прислал и у меня что то не вышло 

Код


import java.util.*;
import java.io.*;

public class zz {
    
     public static Object serialClone(Serializable s)    
      {    
        try    
        {    
          ByteArrayOutputStream byteOut = new ByteArrayOutputStream();    
          ObjectOutputStream objectOut = new ObjectOutputStream(byteOut);    
          objectOut.writeObject(s);    
          objectOut.close();    
          ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());    
          ObjectInputStream objectIn = new ObjectInputStream(byteIn);    
          Object copy = objectIn.readObject();    
          objectIn.close();    
          return copy;    
        }    
        catch(IOException e)
        {    
            return null;// mustn't happend    
          }    
          catch(ClassNotFoundException e)    
          {    
            return null;// mustn't happend    
          }    
        }
     
     public static void main(String[] args) throws Exception    
      {    
        StringBuilder buffer = new StringBuilder("aaa");    
        ArrayList<StringBuilder> list  = new ArrayList<StringBuilder>();    
        list.add(buffer);    
        ArrayList<StringBuilder> copy1  = (ArrayList<StringBuilder>) list.clone();    
        ArrayList<StringBuilder> copy2  = (ArrayList<StringBuilder>) zz.serialClone(list);    
        System.out.println("list  = " + list);    
        System.out.println("copy1 = " + copy1);    
        System.out.println("copy2 = " + copy2);    
        System.out.println("Changing...");    
        buffer.append("bbbb");    
        list.add(new StringBuilder("zzz"));
       
        copy1.get(0).append("ddd");
        copy2.get(0).append("hello");
        
        System.out.println("list  = " + list);    
        System.out.println("copy1 = " + copy1);    
        System.out.println("copy2 = " + copy2);    
        
        
        ArrayList<dd> listDD  = new ArrayList<dd>();    
        listDD.add(new dd(1));
        listDD.add(new dd(2));
        listDD.add(new dd(3));
        listDD.add(new dd(4));
        listDD.add(new dd(5));
        
        ArrayList<dd> copy1_2  = (ArrayList<dd>) listDD.clone();    
        ArrayList<dd> copy2_2  = (ArrayList<dd>) zz.serialClone(listDD);    
        
        
        System.out.println("list  = " + listDD);    
        System.out.println("copy1 = " + copy1_2);    
        System.out.println("copy2 = " + copy2_2);    
        
      }
}


и вот класс экземпляры которого в листе 

Код

public class dd{
    private int a =0;
    
    public dd(int a){
        this.a = a;            
    }
    
    public int  getA(){
        return a;
    }
    
    public void setA(int a){
        this.a = a;
    }
}



и вот вывод 

list  = [aaa]
copy1 = [aaa]
copy2 = [aaa]

Changing...
list  = [aaabbbbddd, zzz]
copy1 = [aaabbbbddd]
copy2 = [aaahello]


list  = [dd@1632c2d, dd@d70d7a, dd@b5f53a, dd@1f6f0bf, dd@137c60d]
copy1 = [dd@1632c2d, dd@d70d7a, dd@b5f53a, dd@1f6f0bf, dd@137c60d]
copy2 = null

почему то на  ArrayList<dd> copy2_2  = (ArrayList<dd>) zz.serialClone(listDD);     не сработало  copy2 = null ?

Может что то с классом не так?

а так всё хорошо работает а с собственным классом не хочет.

Добавлено @ 11:08 

о понял надо ж
Код

 implements Serializable

Автор: Reptor 15.7.2008, 17:26
у меня ещё такой вопрос по поводу сеарилизацыи

если у меня в классе есть внутрений класс то что б он тоже сеарилизовался надо у него тоже указывать implements Serializable. Или у его родителя достаточно??

Просто в зависимости от того указываю я или нет то приложение как то по разному себя ведёт.

Автор: Platon 16.7.2008, 12:06
Все классы должны быть сериализуемыми. 

Автор: Reptor 16.7.2008, 12:54
Platon,  да я смотрю что если во внутренем классе не ставить  implements Serializable то основной совсем не клонируется

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)