자바에서지도의 얕은 사본


106

내가 이해하는 바와 같이 MapJava에서 얕은 복사본을 만드는 몇 가지 방법이 있습니다 .

Map<String, Object> data = new HashMap<String, Object>();
Map<String, Object> shallowCopy;

// first way
shallowCopy = new HashMap<String, Object>(data);

// second way
shallowCopy = (Map<String, Object>) ((HashMap<String, Object>) data).clone();

한 쪽이 다른 쪽보다 선호되며, 그렇다면 그 이유는 무엇입니까?

언급 할 가치가있는 한 가지는 두 번째 방법이 "Unchecked Cast"경고를 제공한다는 것입니다. 따라서 @SuppressWarnings("unchecked")주위를 둘러 보려면 추가 해야합니다. 이는 약간 짜증이납니다 (아래 참조).

@SuppressWarnings("unchecked")
public Map<String, Object> getDataAsMap() {
    // return a shallow copy of the data map
    return (Map<String, Object>) ((HashMap<String, Object>) data).clone();
}

최신 버전의 Java (정확히 Java 10 이후)에서는 Map.copyOf 정적 팩토리 메소드를 사용할 수 있습니다 . 그러나 수정할 수없는지도를 반환합니다!
Oleksandr Pyrohov

답변:


106

항상 복사 생성자를 사용하여 복사하는 것이 좋습니다. clone()Java에서 오류가 발생했습니다 (SO : 복제 방법을 올바르게 재정의하는 방법 참조 ).

디자인에 대한 Josh Bloch-복사 생성자 대 복제

내 책에서 복제에 대한 항목을 읽었다면, 특히 줄 사이를 읽으면 내가 clone깊이 깨 졌다고 생각한다는 것을 알 것 입니다. [...] Cloneable부서진 것이 부끄러운 일이지만 일어납니다.

Bloch (그런데 Collection 프레임 워크를 설계하고 구현 한 사람)는 clone()"사람들이 기대하기 때문에"방법 만 제공한다고 말하기까지 했습니다. 그는 실제로 사용을 전혀 권장하지 않습니다.


더 흥미로운 논쟁은 복사 생성자가 복사 팩토리보다 나은지 여부라고 생각하지만, 그것은 완전히 다른 논의입니다.


1
네, 이것은 책에서 제가 가장 좋아하는 부분 중 하나입니다.
polygenelubricants 2010 년

1
나는 clone ()이 깨 졌다고 말하고 싶지 않습니다. 나는 클론이 끔찍한 디자인 결정이며 올바르게 사용하지 않으면 많은 피해를 입힐 수 있다고 말하는 것을 선호합니다. 또한 다른 사람의 clone () 메서드를 신뢰하지 않을 수도 있습니다. 그래서 우리는 비슷하게 끝나고 그것을 피하려고 노력하지만 깨지지 않았습니다.
santiagobasulto

4
카피 ctor를 사용하기 위해 당신이 카피하고있는 맵 구현을 알아야하지 않습니까? 불필요한 제한처럼 보입니다.
jon-hanson

"그는 단지"사람들이 기대하기 때문에 "clone () 메서드를 제공한다는 것입니다."-소스?
Adam Parkin

60

두 가지 중 어느 것도 참조 하는 생성자MapHashMap 구현에 대해 정의되어 있지 않지만 Map 인터페이스 자체에 대해서는 정의되지 않았습니다 (예 : Map 인터페이스 의 Provider 구현을 고려하십시오 . 생성자를 찾지 못함).

반면 clone()에 Josh Bloch가 설명한대로이 방법 을 사용하는 것은 권장되지 않습니다 .

Map 인터페이스 (및 HashMap이 아닌 Map 복사 방법을 묻는 질문)와 관련하여 Map # putAll () 을 사용해야합니다 .

지정된 맵의 모든 매핑을이 맵에 복사합니다 (선택적 작업). 이 호출의 효과는 지정된 맵에서 키 k에서 값 v 로의 각 매핑에 대해이 맵에서 put (k, v)를 한 번씩 호출하는 것과 같습니다.

예:

// HashMap here, but it works for every implementation of the Map interface
Map<String, Object> data = new HashMap<String, Object>();
Map<String, Object> shallowCopy = new HashMap<String, Object>();

shallowCopy.putAll(data);

2
그래서 명확히하기 위해 : 복사 생성자가 있는 구현에 복사 하는 것을 알고 있다면 복사 생성자를 사용하지 않을 이유가 없습니까? Map
Adam Parkin 2013 년

2
정확히, 당신은 심지어 주변의 다른 방법을 생각할 수 있습니다 : 당신이 사용하는 경우 putAll당신이 알 필요가 없습니다 경우 Map사용중인 구현이 복사 생성자가 아닌지. Map따라서 모든 구현 의 단순한 복사 생성자는 중복됩니다.
Luca Fagioli

1
물론, 일반적으로 나는 2- 라이너보다 1- 라이너를 더 좋아합니다. ;)
Adam Parkin 2013 년

11

구현을 모르고지도를 복사합니다.

static final Map shallowCopy(final Map source) throws Exception {
    final Map newMap = source.getClass().newInstance();
    newMap.putAll(source);
    return newMap;
}

3
<K,V>유형 안전을 보장하려면 유형 매개 변수를 추가하는 것이 좋습니다.
Barett 2015

1
인수가없는 생성자가없는 맵은 어떻습니까?
Isaac Saffold
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.