Javaでのマップの浅いコピー


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();

ある方法が他の方法よりも優先されますか?そうであれば、なぜですか?

言及する価値のあることの1つは、2番目の方法で「未チェックのキャスト」警告が表示されることです。その@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 on Design-コピーコンストラクターと複製

私の本でクローンについての項目を読んだ場合、特に行間を読んだ場合、私cloneは深く壊れていると思います。[...] Cloneable壊れているのは残念ですが、それは起こります。

Bloch(ちなみに、コレクションフレームワークを設計および実装しclone()た人)は、「人々がそれを期待しているから」という方法を提供しているだけだとさらに言っています。彼は実際にそれを使用することを全くお勧めしません。


より興味深い議論は、コピーコンストラクターがコピーファクトリーよりも優れているかどうかですが、それはまったく別の議論です。


1
うん、これは本の私の好きな部分の一つです。
polygenelubricants 2010年

1
clone()が壊れているとは言いたくない。私はクローンはひどい設計上の決定であり、適切に使用しないと多くの害を及ぼす可能性があると言いたいです。また、他の人がclone()メソッドを信頼することは決してないでしょう。ですから、同様の結果になるので、それを避けようとしますが、壊れていません。
santiagobasulto 2011

4
コピートラクターを使用しない場合は、コピーするMapの実装を知る必要がありますか?不要な制限のようです。
jon-hanson

「彼は単に「人々がそれを期待しているから」という理由でclone()メソッドを提供しているだけだ」-ソース?
Adam Parkin 2013年

60

2つのどちらでもありません。参照しているコンストラクターは、MapのHashMap実装(およびその他)に対して定義されていますが、Mapインターフェース自体に対しては定義されていません(たとえば、Mapインターフェースのプロバイダー実装を検討してください:そのコンストラクタは見つかりません)。

一方、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

2
正確に言えば、逆に考えることもできます。使用putAllする場合、使用している実装にコピーコンストラクタがあるどうかを知る必要はありMapません。Mapしたがって、実装の単なるコピーコンストラクタは冗長です。
Luca Fagioli、2013年

1
もちろん、私は通常、2ライナーよりも1ライナーの方が好きです。;)
アダムパーキン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 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.