# HashMap mit Inhalt kopieren



## drAb17 (25. Jul 2010)

Hallo zusammen. ich stehe gerade vor einem Problem, dass ich nicht lösen kann. ich möchte eine HashMap mit ihrem Inhalt kopieren. Und zwar nicht nur die Map, sondern auch die Objekte in ihr. Ich habe es mit putAll() versucht, jedoch kopiert er nur die Map, die Referenzen auf die Objekte sind die selben.
Hier das was ich versucht habe:


```
import java.util.HashMap;


class HashMapExample {

	public static void main(String args[]) {

		HashMap<String, Person> hm = new HashMap<String, Person>();
		hm.put("1", new Person("ich", 100d));

		
		HashMap<String, Person> copyMap = new HashMap<String, Person>();
		
		copyMap.putAll(hm); //???????????????

		Person pers = hm.get("1");
		pers.setChash(-50d);
		
		
		System.out.println(hm.get("1").getChash());
		System.out.println(copyMap.get("1").getChash());
	
	}
}
```
und die Personen Klasse

```
public class Person {
	private String name;
	private double chash;
	
	public Person(String name, double chash) {
		super();
		this.name = name;
		this.chash = chash;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getChash() {
		return chash;
	}
	public void setChash(double chash) {
		this.chash = chash;
	}
	
}
```


----------



## nrg (25. Jul 2010)

überschreib in Person die clone methode und dann erstelle eine deepcopy der map. wenn ich mich nicht irre, erzeugt hm.clone() lediglich eine shallow copy. um eine dc zu erstellen, musste imho durch die inputmap iterieren und jedes objekt einzeln clonen.


----------



## drAb17 (25. Jul 2010)

OK, habe ich nun so gelöst. jedoch denke ich, dass man dies einfacher lösen kann und auch eleganter????? habt ihr ideen? danke !


```
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

class HashMapExample {

	public static void main(String args[]) {

		HashMap<String, Person> hm = new HashMap<String, Person>();
		hm.put("1", new Person("ich", 100d));

		

		HashMap<String, Person> newMap = copyMap(hm);

		Person pers = hm.get("1");
		pers.setChash(-100d);
		
		System.out.println(hm.get("1").getChash());
		System.out.println(newMap.get("1").getChash());
	
	}
	
	private static HashMap<String, Person> copyMap(HashMap<String, Person> map){
		HashMap<String, Person> copyMap = new HashMap<String, Person>();
		
		Set<Entry<String, Person>> set = map.entrySet();
		Iterator<Entry<String, Person>> iter = set.iterator();
		
		while (iter.hasNext()){
			
			Map.Entry<String, Person> me = (Map.Entry<String, Person>) iter.next(); 
			try {
				copyMap.put(me.getKey(), (Person) me.getValue().clone());
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
		}
		return copyMap;
	}
}
```


```
public class Person implements Cloneable{
	private String name;
	private double chash;
	
	public Person(String name, double chash)  {
		super();
		this.name = name;
		this.chash = chash;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getChash() {
		return chash;
	}
	public void setChash(double chash) {
		this.chash = chash;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException{
			return (Person) super.clone();
	}

}
```


----------



## Gelöschtes Mitglied 5909 (25. Jul 2010)

```
@Override
    protected Object clone() throws CloneNotSupportedException{
            return (Person) super.clone();
    }
```

das hilft dir aber nicht. Du musst schon ein neues Objekt erzeugen und den Inhalt kopieren.


----------



## faetzminator (25. Jul 2010)

also so:

```
return new Person(getName(), getChash());
```


----------



## drAb17 (25. Jul 2010)

also mein Beispiel läuft einwandfrei. wollte nur wissen ob es einfacher geht 

die Idee mit dem super.clone() ist von der Insel.

Galileo Computing :: Java ist auch eine Insel (8. Auflage) – 10.2 Object ist die Mutter aller Klassen


habe die Methode nun zu


```
@Override
    protected Person clone() throws CloneNotSupportedException{
            return (Person) super.clone();
    }
```
umgeschrieben, damit ich nicht beim aufruf der Methode nochmals casten muss.

Aber ich denke es geht nun nicht mehr mit weniger code. Bei einer Idee Melden 


Oder gibt es eine Möglichkeit die Methode copyMap, welche die Map kopiert zu generalisieren? evtl. mit Generics? Und so einzuschränken, dass das zweite Argument Cloneable implementieren muss?
Kann mir das jemand zeigen, da ich mit den Generics noch nicht so durchblicke?

DANKE!


----------



## Illuvatar (25. Jul 2010)

drAb17 hat gesagt.:


> Aber ich denke es geht nun nicht mehr mit weniger code. Bei einer Idee Melden



Ich würde es nur mit einer foreach-Schleife kompakter schreiben:

```
private static HashMap<String, Person> copyMap(HashMap<String, Person> map) {
    HashMap<String, Person> copyMap = new HashMap<String, Person>();

    for (Map.Entry<String, Person> entry : map.entrySet()) {
      try {
        copyMap.put(entry.getKey(), entry.getValue().clone());
      } catch (CloneNotSupportedException e) {
        e.printStackTrace();
      }
    }

    return copyMap;
  }
```

Edit:


> Oder gibt es eine Möglichkeit die Methode copyMap, welche die Map kopiert zu generalisieren? evtl. mit Generics? Und so einzuschränken, dass das zweite Argument Cloneable implementieren muss?
> Kann mir das jemand zeigen, da ich mit den Generics noch nicht so durchblicke?


Leider nicht, da das Cloneable-Zeug etwas fürchterliches ist  Wenn es gehen würde, würde es so aussehen:

```
private static <K, V extends Cloneable> HashMap<K, V> copyMap(HashMap<K, V> map) {
    HashMap<K, V> copyMap = new HashMap<K, V>();

    for (Map.Entry<K, V> entry : map.entrySet()) {
      try {
        copyMap.put(entry.getKey(), (V) entry.getValue().clone());
      } catch (CloneNotSupportedException e) {
        e.printStackTrace();
      }
    }

    return copyMap;
  }
```
Leider muss ein Cloneable-Objekt nicht unbedingt eine öffentliche clone-Methode haben...


----------



## drAb17 (25. Jul 2010)

Danke für deine Antwort. Ich habe nun auch gesehen, an welcher Stelle ich meinen Fehler hatte. Ich habe das vorangestellete <T,U> vergessen 

Ich hatte nun die Idee, da einem Cloneable nicht zu einer implementation zwingt folgendes Interface zu schreiben



```
public interface MyCloneable extends Cloneable {
	public Object clone() throws CloneNotSupportedException;
}
```

Meine Frage ist nun, ist das sauber gelöst. sollte man das tun, oder sollte man für jede Map eine eigene copy Methode schreiben ?


Greez


----------



## Illuvatar (25. Jul 2010)

Nach dem DRY-Prinzip ist nur eine copy-Methode deutlich besser 
Die Frage ist eben, ob in den Maps immer nur Objekte sind von Klassen, die du selbst geschrieben hast - sonst können sie halt leider nicht MyCloneable implementieren.

Das Interface könnte man eventuell noch so machen:

```
public interface MyCloneable<T> extends Cloneable {
    public T clone();
}
```
Dann vereinfacht sich die Kopiermethode:

```
private static <K, V extends MyCloneable<V>> HashMap<K, V> copyMap(HashMap<K, V> map) {
    HashMap<K, V> copyMap = new HashMap<K, V>();
    for (Map.Entry<K, V> entry : map.entrySet()) {
      copyMap.put(entry.getKey(), entry.getValue().clone());
    }
    return copyMap;
  }
```


----------

