Java'da bir Haritanın sığ kopyası


107

Anladığım kadarıyla, MapJava'da a'nın sığ bir kopyasını oluşturmanın birkaç yolu (belki diğerleri de) var :

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

Bir yol diğerine tercih edilir ve öyleyse neden?

Bahsetmeye değer bir şey, ikinci yolun "Kontrolsüz Yayın" uyarısı vermesidir. Bu yüzden @SuppressWarnings("unchecked")etrafından dolaşmak için eklemelisiniz ki bu biraz rahatsız edici (aşağıya bakın).

@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'nın daha yeni sürümlerinde (tam olarak Java 10'dan beri) Map.copyOf statik fabrika yöntemini kullanabilirsiniz. Ancak değiştirilemez bir Harita döndürdüğünü unutmayın!
Oleksandr Pyrohov

Yanıtlar:


106

Bir kopya oluşturucu kullanarak kopyalamak her zaman daha iyidir. clone()Java'da bozuk (bkz. SO: Klon yöntemi nasıl düzgün bir şekilde geçersiz kılınır? ).

Josh Bloch on Design - Oluşturucuyu Kopyala ve Klonlama

Kitabımdaki klonlama ile ilgili maddeyi okuduysanız, özellikle satır aralarını okursanız clone, derinden kırıldığını düşündüğümü anlayacaksınız . [...] CloneableKırılan bir utanç ama oluyor.

Bloch (bu arada, Koleksiyon çerçevesini tasarlayan ve uygulayan), clone()yöntemi yalnızca "insanlar beklediği için" sağladığını söyleyerek daha da ileri gitti . Aslında onu kullanmayı tavsiye ETMEZ.


Bence daha ilginç tartışma, bir kopya kurucusunun bir kopya fabrikasından daha iyi olup olmadığıdır, ancak bu tamamen farklı bir tartışma.


1
Evet, bu kitabın en sevdiğim bölümlerinden biri.
poligenel yağlayıcılar

1
Clone () 'un bozuk olduğunu söylemekten hoşlanmıyorum. Klonun korkunç bir tasarım kararı olduğunu ve doğru kullanmazsanız size çok zarar verebileceğini söylemeyi tercih ediyorum. Ayrıca, başkalarının clone () yöntemlerine asla güvenmeyebilirsiniz. Böylece benzer hale geliyoruz, ondan kaçınmaya çalışıyoruz, ama bu kırılmamış.
santiagobasulto

4
Copy ctor'u kullanmak, hangi Harita uygulamasını kopyaladığınızı bilmenizi gerektirmiyor mu? Gereksiz bir sınırlama gibi görünüyor.
jon-hanson

"sadece clone () yöntemini sağladığını" çünkü insanlar beklediği için "" - kaynak?
Adam Parkin

60

İkisi de: Bahsettiğiniz kurucu , bir Haritanın HashMap uygulaması için tanımlanmıştır (ve diğerleri için olduğu gibi), ancak Harita arayüzünün kendisi için tanımlanmamıştır (örneğin, Harita arayüzünün Sağlayıcı uygulamasını düşünün : siz kurucuyu bulamayacak).

Öte yandan clone(), Josh Bloch tarafından açıklandığı gibi yöntemin kullanılması tavsiye edilmez .

Harita arayüzü (ve bir HashMap'i değil, bir Haritayı nasıl kopyalayacağınızı sorduğunuz sorunuz için), Map # putAll () kullanmalısınız :

Belirtilen haritadan tüm eşlemeleri bu haritaya kopyalar (isteğe bağlı işlem). Bu çağrının etkisi, belirtilen haritadaki k anahtarından v değerine her eşleme için bu haritadaki put (k, v) 'yi çağırmanın etkisine eşdeğerdir.

Misal:

// 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
Öyleyse açıklığa kavuşturmak için: Kopya oluşturucusuna sahip bir uygulamaya kopyaladığınızı biliyorsanız , kopya yapıcısını kullanmamanız için hiçbir neden yoktur? Map
Adam Parkin

2
Kesinlikle ve hatta tam tersi bunu düşünebilirsiniz: Eğer kullanırsanız putAllsize bilmeniz gerekmez eğer Mapkullandığınız uygulama bir kopya kurucu vardır ya da değil. Bu Mapnedenle , herhangi bir uygulamanın sadece bir kopya kurucusu gereksizdir.
Luca Fagioli

1
Elbette, ancak genellikle 1 astarlıları 2 astarlılardan daha çok seviyorum. ;)
Adam Parkin

11

Uygulamasını bilmeden bir haritayı kopyalayın:

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

3
<K,V>Tür güvenliğini sağlamaya yardımcı olması için tür parametreleri eklemeyi düşünün .
Barett

1
Sıfır bağımsız değişken kurucuları olmayan haritalar ne olacak?
Isaac Saffold
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.