[java] Java Collections 목록을 복사하는 방법

나는 ArrayList 정확하게 복사하고 싶습니다. 누군가가 올바른 시간을 보냈다는 가정하에 가능하면 유틸리티 클래스를 사용합니다. 그래서 자연스럽게, 나는 Collections복사 방법을 포함하는 클래스로 끝납니다 .

내가 다음을 가지고 있다고 가정하십시오.

List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a.size());

Collections.copy(b,a);

기본적으로 b크기가 충분하지 않다고 생각하기 때문에 실패합니다 a. 예 b, 크기가 0이라는 것을 알고 있지만 이제는 커야합니까? 내가 b먼저 채워야한다면 , Collections.copy()내 마음에 완전히 쓸모없는 기능이됩니다. 복사 기능 프로그래밍 (지금 할 것)을 제외하고는 이것을 수행하는 적절한 방법이 있습니까?



답변

부름

List<String> b = new ArrayList<String>(a);

awithin 의 얕은 사본을 만듭니다 b. 모든 요소는 b순서와 동일한 순서대로 존재합니다 a.

마찬가지로 전화

// note: instantiating with a.size() gives `b` enough capacity to hold everything
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b, a);

awithin 의 얕은 사본을 만듭니다 b. 첫 번째 매개 변수에 모든 요소 를 포함 b 있는 충분한 용량 (크기가 아님) a이없는 경우을 발생 IndexOutOfBoundsException시킵니다. 예상 Collections.copy대로 작동하는 데 할당이 필요하지 않으며 ,있는 경우 해당 예외가 발생합니다. 복사 된 컬렉션을 미리 할당해야하는 최적화입니다 (b ). 일반적으로 위의 그림과 같이 이상한 부작용이없는 생성자 기반 대안이 주어지면 필요한 검사로 인해 기능이 가치가 있다고 생각하지 않습니다.

딥 카피를 만들려면 List두 메커니즘 중 하나를 통해 기본 유형에 대한 복잡한 지식이 있어야합니다. StringJava (및 해당 문제의 경우 .NET)에서 변경할 수없는 s 의 경우 딥 카피조차 필요하지 않습니다. 의 경우 MySpecialObject, 사본을 만드는 방법을 알아야하며 이는 일반적인 작업이 아닙니다.


참고 : 원래 허용 된 답변은 Collections.copyGoogle에서 최고 결과 였으며 의견에서 지적한대로 잘못 표시되었습니다.


답변

b보유 용량이 3이지만 크기 0 사실 ArrayList는 부분 아니다 – 버퍼 용량 일종의 구현 상세 가지고 List있으므로 인터페이스 Collections.copy(List, List)를 사용하지 않고있다. 특별한 경우에는 추한 것 ArrayList입니다.

MrWiggles가 지적했듯이, 컬렉션을 취하는 ArrayList 생성자를 사용하는 것이 제공된 예제의 방법입니다.

더 복잡한 시나리오 (실제 코드를 포함 할 수 있음)의 경우 구아바 내의 모음이 유용 할 수 있습니다 .


답변

그냥 해:

List a = new ArrayList();
a.add("a");
a.add("b");
a.add("c");
List b = new ArrayList(a);

ArrayList에는 다른 Collection을 받아 요소를 복사하는 생성자가 있습니다.


답변

Stephen Katulka의 답변 (허용 된 답변)이 잘못되었습니다 (두 번째 부분). 그것은 Collections.copy(b, a);딥 카피 를 수행 한다고 설명 하지만 그렇지 않습니다. 둘, new ArrayList(a);그리고 Collections.copy(b, a);단지 얕은 사본을한다. 차이점은 생성자가 새 메모리를 할당 copy(...)하지만 그렇지 않은 경우 성능 이점이 있으므로 배열을 재사용 할 수있는 경우에 적합하다는 것입니다.

Java 표준 API는 딥 카피 사용을 권장하지 않습니다. 새로운 코더가 정기적으로 이것을 사용하면 좋지 않을 수 있습니다 clone(). 이는 기본적으로 공개되지 않는 이유 중 하나 일 수도 있습니다 .

소스 코드는 Collections.copy(...)552 행에서 확인할 수 있습니다.
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/ Collections.java.htm

딥 카피가 필요한 경우 각 객체에서 for 루프와 clone ()을 사용하여 항목을 수동으로 반복해야합니다.


답변

List를 복사하는 가장 간단한 방법은 새 목록의 생성자에게 전달하는 것입니다.

List<String> b = new ArrayList<>(a);

b 얕은 사본이 될 것입니다 a

Collections.copy(List,List)(나는 전에 본 적이 없다) 의 출처를 보면 인덱스로 요소 색인을 처리하는 것으로 보입니다. List.set(int,E)따라서 요소 0을 사용 하면 대상 목록 등의 요소 0을 덮어 씁니다. 인정해야 할 javadoc에서 특별히 명확하지 않습니다.

List<String> a = new ArrayList<>(a);
a.add("foo");
b.add("bar");

List<String> b = new ArrayList<>(a); // shallow copy 'a'

// the following will all hold
assert a.get(0) == b.get(0);
assert a.get(1) == b.get(1);
assert a.equals(b);
assert a != b; // 'a' is not the same object as 'b'


답변

List b = new ArrayList(a.size())

크기를 설정하지 않습니다. 초기 용량을 설정합니다 (크기를 조정하기 전에 몇 개의 요소를 넣을 수 있는지). 이 경우 더 간단한 복사 방법은 다음과 같습니다.

List b = new ArrayList(a);


답변

Hoijui가 언급했듯이. Stephen Katulka가 선택한 답변에 Collections.copy에 대한 의견이 잘못되었습니다. 저자는 아마도 첫 번째 코드 행이 원하는 사본을 작성했기 때문에 승인했을 것입니다. Collections.copy에 대한 추가 호출은 다시 복사됩니다. (복사 결과 두 번 발생 함).

그것을 증명하는 코드는 다음과 같습니다.

public static void main(String[] args) {

    List<String> a = new ArrayList<String>();
    a.add("a");
    a.add("b");
    a.add("c");
    List<String> b = new ArrayList<String>(a);

    System.out.println("There should be no output after this line.");

    // Note, b is already a shallow copy of a;
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) != b.get(i)) {
            System.out.println("Oops, this was a deep copy."); // Note this is never called.
        }
    }

    // Now use Collections.copy and note that b is still just a shallow copy of a
    Collections.copy(b, a);
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) != b.get(i)) {
            System.out.println("Oops, i was wrong this was a deep copy"); // Note this is never called.
        }
    }

    // Now do a deep copy - requires you to explicitly copy each element
    for (int i = 0; i < a.size(); i++) {
        b.set(i, new String(a.get(i)));
    }

    // Now see that the elements are different in each 
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) == b.get(i)) {
            System.out.println("oops, i was wrong, a shallow copy was done."); // note this is never called.
        }
    }
}