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.
        }
    }
}