Java에서 일반 목록을 어떻게 복제합니까?


155

나는이 ArrayList<String>내가 사본을 반환하고 싶습니다있다. ArrayList다음 서명이있는 복제 방법이 있습니다.

public Object clone()

이 메서드를 호출 한 후 반환 된 Object를 ArrayList<String>어떻게 다시 캐스팅 합니까?


16
아니요, 이것은 유효한 질문입니다. Java는 런타임 유형 삭제 등을 포함한 "true"제네릭을 지원하지 않으므로 이러한 종류의 세부 정보는 까다로울 수 있습니다. 또한 Cloneable 인터페이스와 Object.clone () 메서드 메커니즘도 비슷하게 혼동됩니다.
무법자 프로그래머

좋아, 나는 이것이 정말로 쉬운 C #을 주로한다. 이 질문에서 주석을 제거하려면 알려 주시기 바랍니다.
Espo

1
당신은 의견을 남길 수 있습니다. 편집 한 내용에 문제가 있다고 설명했습니다.
Bill the Lizard

2
당신의 의견은 조금 혼란스러워도 괜찮습니다. Java 개발자가 .NET 개발자에게는 어리석은 것처럼 보이는 많은 후프가 있다고 생각합니다.
무법자 프로그래머

1
@Oscar는 복제 명령을 실행하지 않고 복제하려고합니다. 클론이 실제로 복제하지 않는 것과 동일하지 않을 수 있습니다. 이것이 요점이라고 생각합니다. 이것은 실제로 까다로운 질문입니다.
Rafa

답변:


62
ArrayList newArrayList = (ArrayList) oldArrayList.clone();

43
이것은 Strings (질문과 같은)에서 잘 작동하지만 ArrayList.clone이 얕은 복사를 수행한다는 점에 주목할 가치가 있습니다. 따라서 목록에 변경 가능한 객체가 있으면 복제되지 않습니다 (그리고 하나를 변경) 한 목록에서 다른 목록으로 변경 될 것입니다
pkaeding

49
레거시 코드 외에는 원시 형식을 사용하지 않아야합니다. 을 사용하는 것이 좋습니다 ArrayList<String> newArrayList = (ArrayList<String>) oldArrayList.clone();.
cdmckay

20
너무 나쁘다 ArrayList는 #clone 메소드를 가지고 있지만 List 자체는 그렇지 않습니다. 한숨.
rogerdpack

12
관련이 없지만 그 동안 : 왼쪽 List<String>대신에 사용 ArrayList<String>하십시오. 컬렉션이 대부분 사용되는 방식입니다.
Christophe Roussy

3
이 메서드를 사용하여 ArrayList를 복제 할 수 없습니다. clone () 메소드가 인식되지 않았습니다.
Jack

318

왜 복제하고 싶습니까? 일반적으로 새 목록을 만드는 것이 더 합리적입니다.

List<String> strs;
...
List<String> newStrs = new ArrayList<>(strs);

작업이 완료되었습니다.


17
어떤 유형의 목록인지 알 수 없습니다. LinkedList, MyOwnCustomList 또는 ArrayList의 서브 클래스 일 수 있습니다.이 경우 ArrayList를 새로 작성하는 것이 올바르지 않은 유형입니다.
Steve Kuo

51
원래 목록이 사용 된 구현에 관심이 있습니까? 아마도 새로운 목록이 어떤 구현을 사용하는지 신경 쓸 것입니다.
Tom Hawtin-tackline

12
@Steve Kuo : 서명은 ArrayList(Collection<? extends E> c)어떤 종류의 목록을 인수로 사용하든 상관 없습니다.
cdmckay

3
딥 카피가 아닙니까?

4
아니에요.
Tom Hawtin-tackline

19

이것은 내가 사용하는 코드입니다.

ArrayList copy = new ArrayList (original.size());
Collections.copy(copy, original);

희망은 당신에게 유용합니다


3
그리고 원시 타입을 사용하지 마십시오. 대신 ArrayList사용ArrayList<YourObject>
milosmns

2
docs.oracle.com/javase/8/docs/api/java/util/… 목록 크기가 다르기 때문에 작동하지 않습니다.
MLProgrammer-CiM

ArrayList생성자 의 복사 과부하를 사용하지 않습니까?
Tom Hawtin-tackline

19

Java 8에서는 스트림으로 복제 할 수 있습니다.

import static java.util.stream.Collectors.toList;

...

List<AnObject> clone = myList.stream().collect(toList());

List <AnObject> xy = new ArrayList <> (oldList)와 같이 수행 할 수 있습니다.
mirzak

1
이것은 딥 카피가 아니며, 한 목록의 요소에 대한 변경 사항은 다른 목록에서 볼 수 있습니다
Inchara

2
질문에서 어디에 깊은 사본이 필요하다고 지정합니까? 동일한 객체를 포함하는 다른 컬렉션이 필요하다고 가정합니다. 딥 카피 경로를 내려 가려면 완전히 새로운 웜 캔을 열어야합니다.
사이먼 젠킨스

그래도 클론은 아닙니다. 그렇지 않습니까? API 문서에서 "반환 된 List의 유형, 변경 가능성, 직렬화 가능성 또는 스레드 안전성에 대한 보장은 없습니다". Euw, 그중 하나를 원하지 않습니다. toCollection더 나은 선택 일 수 있습니다.
Tom Hawtin-tackline

16

Object.clone ()에는 몇 가지 중요한 문제가 있으며 대부분의 경우 사용을 권장하지 않습니다. 자세한 답변은 Joshua Bloch의 " Effective Java "의 항목 11을 참조하십시오 . 기본 유형 배열에서 Object.clone ()을 안전하게 사용할 수 있다고 생각하지만 클론을 올바르게 사용하고 재정의하는 것에 대해서는 신중해야합니다. 의미에 따라 객체를 명시 적으로 복제하는 복사 생성자 또는 정적 팩토리 메소드를 정의하는 것이 좋습니다.


15

이것이 Collections API를 사용하여 트릭을 수행해야한다고 생각합니다.

참고 : 복사 방법은 선형 시간으로 실행됩니다.

//assume oldList exists and has data in it.
List<String> newList = new ArrayList<String>();
Collections.copy(newList, oldList);

13
왜 new ArrayList <String> (oldList)를 사용하지 않습니까?
cdmckay

4
나는 이것이 문서에서 작동하지 않을 것이라고 생각한다. * 목적지 목록은 최소한 소스 목록만큼 길어야한다. 더 길면 대상 목록의 나머지 요소는 영향을받지 않습니다.
Greg Domjan

@GregDomjan이 방법이 최선의 방법이라는 데 동의하지는 않지만 그렇게하는 방법입니다. 문제를 해결하려면 다음과 같이 간단합니다. List <String> newList = new ArrayList <> (oldList.size ());
nckbrz 2016 년

1
Java 8과 관련이 있는지 확실하지 않지만 크기를 지정할 때도 여전히 예외가 발생합니다. IndexOutOfBoundsException : destination.size () <source.size () : 0 <2 on List<MySerializableObject> copyList = new ArrayList<>(mMySerializableObjects.size()); 사용 copyList.addAll(original);하는 것이 좋은 대안 인 것 같습니다
Gene Bo

@GeneBo 크기를 지정하지 않습니다. 용량을 지정합니다. 이는 매우 다른 것입니다. 미스터리 int논쟁 의 기쁨 . 나는 왜 당신이 좋은 오래된 대신이 모호한 정적 메소드를 사용하고 싶어하는지 모른다 addAll.
Tom Hawtin-tackline

8

addAll을 사용하면 정상적으로 작동합니다.

ArrayList<String> copy = new ArrayList<String>();
copy.addAll(original);

제네릭 구문 대신 괄호가 사용됩니다.


5
문자열에서는 작동하지만 변경 가능한 객체에는 작동하지 않습니다. 그것들도 복제하고 싶을 것입니다.
jodonnell

네, 그의 질문은 문자열입니다. 그리고 그는이 경우 주조 물건을 정말로 좋아하지 않는 제네릭의 문제가 있습니다.
Allain Lalonde

또한 ArrayList.clone은 얕은 복제 만 수행하므로 목록의 변경 가능한 개체는 해당 방법을 사용하여 복제되지 않습니다.
pkaeding

ArrayList <String> btw 여야합니다. 또한 새 ArrayList <String> (original)을 사용하는 것이 적고 명확하기 때문에 새 ArrayList <String> (original)을 사용하는 것이 좋습니다.
cdmckay

4
왜 사용하지 new ArrayList<String>(original)않습니까?
user102008

6

getter에서 List를 반환 할 수 있도록하려면 다음을 수행하는 것이 좋습니다.

ImmutableList.copyOf(list);

4

일반 인터페이스를 복제하려면 java.util.List캐스트 만하면됩니다. 여기 예가 있습니다 :

List list = new ArrayList();
List list2 = ((List) ( (ArrayList) list).clone());

약간 까다 롭지 만 List인터페이스 를 반환하도록 제한되어 있으면 원하는 경우 언제든지 목록을 구현할 수 있습니다.

나는이 답변이 최종 답변에 가깝다는 것을 알고 있지만, 내 대답은 당신이 List일반적인 부모-ArrayList


2
당신은 그것이 항상 사실이 아닌 ArrayList라고 가정합니다
jucardi

@ JuanCarlosDiaz 것입니다, 이것은 질문입니다, 그것은 ArrayList에 관한 것입니다, 그래서 나는 ArrayList에 대한 답변 :)
Ahmed Hamdy

2

ArrayList를 복제 할 때 매우주의하십시오. 자바 복제는 얕다. 이는 멤버가 아닌 Arraylist 자체 만 복제한다는 것을 의미합니다. 따라서 ArrayList X1이 있고 X2로 복제하면 X2의 모든 변경 사항이 X1에도 나타나고 그 반대도 마찬가지입니다. 복제 할 때 원본의 동일한 요소에 대한 포인터가있는 새 ArrayList 만 생성합니다.


2

이것은 또한 작동해야합니다 :

ArrayList<String> orig = new ArrayList<String>();
ArrayList<String> copy = (ArrayList<String>) orig.clone()

2
List<String> shallowClonedList = new ArrayList<>(listOfStrings);

이것은 딥 카피가 아니라 얕은 것입니다. 새 목록을 얻지 만 항목은 동일합니다. 단순히 문자열에는 문제가 없습니다. 목록 항목이 객체 자체 인 경우 더 까다로워집니다.


1
ArrayList first = new ArrayList ();
ArrayList copy = (ArrayList) first.clone ();

1

나는 자바 전문가가 아니지만 같은 문제가 있으며이 방법으로 해결하려고했습니다. (T에 복사 생성자가 있다고 가정합니다).

 public static <T extends Object> List<T> clone(List<T> list) {
      try {
           List<T> c = list.getClass().newInstance();
           for(T t: list) {
             T copy = (T) t.getClass().getDeclaredConstructor(t.getclass()).newInstance(t);
             c.add(copy);
           }
           return c;
      } catch(Exception e) {
           throw new RuntimeException("List cloning unsupported",e);
      }
}

List구현 클래스에 인수없는 공용 생성자가 있다고 보장 할 수 없습니다. 예를 들어, List반환에 의해이야 Array.asList, List.of또는 List.subList아마하지 않습니다.
Tom Hawtin-tackline
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.