publicDog(Dog dog) { // Copy all the fields of Dog. } }
Затем просто выполните итерацию (как показано в ответе Вархана):
publicstatic List<Dog> cloneList(List<Dog> dogList) { List<Dog> clonedList = newArrayList<Dog>(dogList.size()); for (Dog dog : dogList) { clonedList.add(newDog(dog)); } return clonedList; }
Я нахожу преимущество этого в том, что вам не нужно возиться со сломанными клонируемыми материалами в Java. Это также соответствует способу копирования коллекций Java.
Другим вариантом может быть написание собственного ICloneable интерфейса и использование его. Таким образом, вы могли бы написать универсальный метод для клонирования.
Ответ 2
Вам нужно будет выполнять итерации по элементам и клонировать их один за другим, по ходу помещая клоны в результирующий массив.
Учитывая все проблемы, связанные с Cloneable, можно с уверенностью сказать, что другие интерфейсы не должны расширять его, и что классы, предназначенные для наследования (пункт 17), не должны его реализовывать. Из-за множества его недостатков некоторые опытные программисты просто предпочитают никогда не переопределять метод clone и никогда не вызывать его, за исключением, возможно, копирования массивов. Если вы разрабатываете класс для наследования, имейте в виду, что если вы решите не предоставлять хорошо работающий защищенный метод клонирования, подклассы не смогут реализовать Cloneable.
В этой книге также описывается множество преимуществ конструкторов копирования перед Cloneable / clone.
Они не полагаются на механизм создания экстралингвистических объектов, подверженных риску
Они не требуют принудительного соблюдения слабо документированных соглашений
Они не конфликтуют с правильным использованием конечных полей
Они не выдают ненужных проверяемых исключений
Они не требуют приведений.
Рассмотрим еще одно преимущество использования конструкторов копирования: предположим, у вас есть HashSet s, и вы хотите скопировать его как TreeSet. Метод clone не может предложить такую функциональность, но это легко сделать с конструктором преобразования: new TreeSet(s).
Ответ 4
Java 8 предоставляет новый способ элегантного и компактного вызова конструктора копирования или метода клонирования элементов dogs: Streams, лямбды и коллекторы.
Выражение Dog::new называется ссылкой на метод. Оно создает объект-функцию, который вызывает конструктор Dog, который принимает другой dog в качестве аргумента.
Если вам не нужно сохранять исходное содержимое dogs списка, вы можете вместо этого использовать replaceAll метод и обновить список на месте:
dogs.replaceAll(Dog::new);
Все примеры предполагают import static java.util.stream.Collectors.*;.
Сборщик для ArrayLists
Коллектор из последнего примера можно преобразовать в метод util. Поскольку это такая распространенная вещь, мне лично нравится, чтобы она была короткой и красивой. Вот так:
Для работы этого решения clone метод Dogне должен объявлять, что он выдает CloneNotSupportedException. Причина в том, что аргументу map не разрешено создавать какие-либо проверенные исключения.
Вот так:
// Note: Method is public and returns Dog, not Object @Override public Dog clone()/* Note: No throws clause here */ { ...
Однако это не должно быть большой проблемой, поскольку в любом случае это лучшая практика. (Например, Effectice Java дает такой совет.)