답변:
항목을 반복하고 하나씩 복제하여 복제를 결과 배열에 배치해야합니다.
public static List<Dog> cloneList(List<Dog> list) {
List<Dog> clone = new ArrayList<Dog>(list.size());
for (Dog item : list) clone.add(item.clone());
return clone;
}
이를 위해서는 Dog
클래스가 Cloneable
인터페이스 를 구현 하고 clone()
메서드를 재정의하도록해야 합니다.
개인적으로 Dog에 생성자를 추가합니다.
class Dog
{
public Dog()
{ ... } // Regular constructor
public Dog(Dog dog) {
// Copy all the fields of Dog.
}
}
그런 다음 Varkhan의 답변에 표시된 것처럼 반복하십시오.
public static List<Dog> cloneList(List<Dog> dogList) {
List<Dog> clonedList = new ArrayList<Dog>(dogList.size());
for (Dog dog : dogList) {
clonedList.add(new Dog(dog));
}
return clonedList;
}
이것의 장점은 Java에서 깨진 Cloneable 항목으로 해결할 필요가 없다는 것입니다. 또한 Java 콜렉션을 복사하는 방법과 일치합니다.
또 다른 옵션은 ICloneable 인터페이스를 직접 작성하여 사용하는 것입니다. 그렇게하면 복제를위한 일반적인 방법을 작성할 수 있습니다.
cloneList(List<Object>)
나 Dog(Object)
?
모든 표준 컬렉션에는 복사 생성자가 있습니다. 그것을 써.
List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original); //This does a shallow copy
clone()
여러 가지 실수로 설계되었으므로 ( 이 질문 참조 ) 피하는 것이 가장 좋습니다.
에서 효과적인 자바 2 판 , 항목 11 : 재정의 클론 신중하게
Cloneable과 관련된 모든 문제가 주어지면 다른 인터페이스가 확장해서는 안되며 상속을 위해 설계된 클래스 (항목 17)는 구현해서는 안된다고 말하는 것이 안전합니다. 많은 단점이 있기 때문에 일부 전문가 프로그래머는 단순히 복제 방법을 재정의하지 않고 배열을 복사하는 것 외에는 호출하지 않기로 결정합니다. 상속을 위해 클래스를 디자인 할 경우, 잘 동작하는 보호 된 클론 메소드를 제공하지 않기로 선택하면 서브 클래스가 Cloneable을 구현할 수 없습니다.
이 책은 또한 복사 생성자가 복제 가능 / 복제에 비해 많은 장점을 설명합니다.
복사 생성자를 사용하는 또 다른 이점을 고려 : 당신은이 가정 HashSet s
, 당신은로 복사 할 TreeSet
. clone 메소드는이 기능을 제공 할 수 없지만 다음과 같이 변환 생성자를 사용하면 쉽습니다 new TreeSet(s)
.
: 자바 8 우아하고 컴팩트 요소 개에 복사 생성자 또는 복제 메서드를 호출 할 수있는 새로운 방법을 제공합니다 스트림 , 람다 및 수집을 .
복사 생성자 :
List<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toList());
표현식을 메소드 참조Dog::new
라고합니다 . 다른 개를 인수로 취하는 생성자를 호출하는 함수 객체를 만듭니다 .Dog
복제 방법 [1] :
List<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toList());
ArrayList
결과로 얻기또는 ArrayList
다시 연락 을 받아야하는 경우 (나중에 수정하려는 경우) :
ArrayList<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toCollection(ArrayList::new));
dogs
목록 의 원래 내용을 유지할 필요가없는 경우 대신 replaceAll
방법을 사용하여 목록을 업데이트하십시오.
dogs.replaceAll(Dog::new);
모든 예제는 가정 import static java.util.stream.Collectors.*;
합니다.
ArrayList
의마지막 예제의 콜렉터는 util 메소드로 만들 수 있습니다. 이것은 일반적인 일이기 때문에 나는 개인적으로 짧고 예쁘기를 좋아합니다. 이처럼 :
ArrayList<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toArrayList());
public static <T> Collector<T, ?, ArrayList<T>> toArrayList() {
return Collectors.toCollection(ArrayList::new);
}
CloneNotSupportedException
:이 솔루션이 작동하려면의 clone
메소드 가이를 선언한다고 선언 Dog
해서는 안됩니다CloneNotSupportedException
. 그 이유는 인수가 map
점검 된 예외를 처리 할 수 없기 때문입니다 .
이처럼 :
// Note: Method is public and returns Dog, not Object
@Override
public Dog clone() /* Note: No throws clause here */ { ...
그러나 이것이 가장 좋은 방법이므로 큰 문제는 아닙니다. ( 예를 들어 Effect Java 는이 조언을 제공합니다.)
이 사실을 알려 주신 Gustavo에게 감사드립니다.
더 예쁘다면 대신 메소드 참조 구문을 사용하여 똑같은 일을 할 수 있습니다.
List<Dog> clonedDogs = dogs.stream().map(Dog::clone).collect(toList());
List<Dog> clonedDogs = new ArrayList<>(); dogs.stream().parallel().forEach(d -> clonedDogs.add(new Dog(d)));
parallel
호출이 clonedDogs.add
여러 스레드에서 동시에 호출 되기 때문 입니다. 사용하는 버전 collect
은 스레드로부터 안전합니다. 이것은 스트림 라이브러리의 기능 모델의 장점 중 하나이며, 동일한 코드를 병렬 스트림에 사용할 수 있습니다.
Unhandled exception type CloneNotSupportedException
에 d.clone()
. 예외를 선언하거나 잡으면 해결되지 않습니다.
Dog
이 예에서는)가 복제를 지원하지 않기 때문에 거의 확실합니다 . Clonable
인터페이스를 구현 하시겠습니까?
기본적으로 수동 반복없이 세 가지 방법이 있습니다.
1 생성자 사용
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>(dogs);
2 사용 addAll(Collection<? extends E> c)
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(dogs);
3 파라미터 addAll(int index, Collection<? extends E> c)
와 함께 방법 사용int
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(0, dogs);
NB : 작업이 진행되는 동안 지정된 컬렉션이 수정되면 이러한 작업의 동작이 정의되지 않습니다.
나는 현재 녹색 답변이 나쁘다고 생각합니다 . 왜 물어 볼까요?
직렬화도 좋지 않은 방법으로, 모든 곳에서 직렬화 가능을 추가해야 할 수도 있습니다.
그래서 해결책은 무엇입니까?
자바 라이브러리를 깊은 복제 클로닝 라이브러리는 작은 오픈 소스 (아파치 라이선스) 자바 라이브러리 깊은 클론 객체입니다. 객체는 Cloneable 인터페이스를 구현할 필요가 없습니다. 사실상이 라이브러리는 모든 Java 객체를 복제 할 수 있습니다. 캐시 된 개체를 수정하지 않으려는 경우 또는 개체의 깊은 복사본을 만들 때마다 캐시 구현에서 사용할 수 있습니다.
Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);
json을 사용하여 목록을 직렬화 / 직렬화 해제 할 수있는 방법을 찾았습니다. 직렬화리스트는 직렬화 해제시 원래 오브젝트에 대한 참조를 보유하지 않습니다.
gson 사용하기 :
List<CategoryModel> originalList = new ArrayList<>(); // add some items later
String listAsJson = gson.toJson(originalList);
List<CategoryModel> newList = new Gson().fromJson(listAsJson, new TypeToken<List<CategoryModel>>() {}.getType());
jackson과 다른 json 라이브러리를 사용하여 그렇게 할 수 있습니다.
ArrayList
수동 으로 복제해야합니다 (반복하고 각 요소를 새 요소에 복사하여 ArrayList
) clone()
. 그 이유는에 포함 된 객체가 자체적으로 ArrayList
구현되지 않았기 Clonable
때문입니다.
편집 : ... 그것이 바로 Varkhan의 코드가하는 일입니다.
불쾌한 방법은 반사와 함께하는 것입니다. 이와 같은 것이 나를 위해 일했습니다.
public static <T extends Cloneable> List<T> deepCloneList(List<T> original) {
if (original == null || original.size() < 1) {
return new ArrayList<>();
}
try {
int originalSize = original.size();
Method cloneMethod = original.get(0).getClass().getDeclaredMethod("clone");
List<T> clonedList = new ArrayList<>();
// noinspection ForLoopReplaceableByForEach
for (int i = 0; i < originalSize; i++) {
// noinspection unchecked
clonedList.add((T) cloneMethod.invoke(original.get(i)));
}
return clonedList;
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
System.err.println("Couldn't clone list due to " + e.getMessage());
return new ArrayList<>();
}
}
original
다른 클래스의 객체가 포함되어 있으면 cloneMethod.invoke
잘못된 종류의 객체로 호출하면 예외로 실패 한다고 생각 합니다. 이 때문에 Method
각 객체에 대해 특정 클론을 검색하는 것이 좋습니다 . 또는 clone 메소드를 사용하십시오 Object
(그러나 그 방법 은 보호되어 더 많은 경우 실패 할 수 있습니다).
다음은 일반적인 템플릿 유형을 사용하는 솔루션입니다.
public static <T> List<T> copyList(List<T> source) {
List<T> dest = new ArrayList<T>();
for (T item : source) { dest.add(item); }
return dest;
}
javas 라이브러리를 commons-lang-2.3.jar를 사용하여 목록을 복제하여 쉬운 방법
사용하는 방법
oldList.........
List<YourObject> newList = new ArrayList<YourObject>();
foreach(YourObject obj : oldList){
newList.add((YourObject)SerializationUtils.clone(obj));
}
나는 이것이 도움이되기를 바랍니다.
:디
방금 엔터티 객체와 java.util.List 객체를 복제 할 수있는 lib를 개발했습니다. https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U 에서 항아리를 다운로드하고 정적 메소드 cloneListObject (List list)를 사용하십시오. 이 메소드는 List뿐만 아니라 모든 엔티티 요소를 복제합니다.
아래는 나를 위해 일했다 ..
Dog.java에서
public Class Dog{
private String a,b;
public Dog(){} //no args constructor
public Dog(Dog d){ // copy constructor
this.a=d.a;
this.b=d.b;
}
}
-------------------------
private List<Dog> createCopy(List<Dog> dogs) {
List<Dog> newDogsList= new ArrayList<>();
if (CollectionUtils.isNotEmpty(dogs)) {
dogs.stream().forEach(dog-> newDogsList.add((Dog) SerializationUtils.clone(dog)));
}
return newDogsList;
}
createCopy 메소드에서 작성된 새 목록은 SerializationUtils.clone ()을 통해 작성됩니다. 따라서 새 목록을 변경해도 원래 목록에는 영향을 미치지 않습니다.
딥 카피 ArrayList를 만드는 가장 쉬운 방법을 찾았습니다. String ArrayList arrayA를 복사한다고 가정합니다.
ArrayList<String>arrayB = new ArrayList<String>();
arrayB.addAll(arrayA);
그것이 효과가 없다면 알려주세요.