HashMap mit Inhalt kopieren

drAb17

Mitglied
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:

Java:
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
Java:
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;
	}
	
}
 
ü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.
 
OK, habe ich nun so gelöst. jedoch denke ich, dass man dies einfacher lösen kann und auch eleganter????? habt ihr ideen? danke !

Java:
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;
	}
}
Java:
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();
	}

}
 
Java:
    @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.
 
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

Java:
    @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!
 
Zuletzt bearbeitet:
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:
Java:
  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:
Java:
  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... 😳
 
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


Java:
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
 
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:
Java:
public interface MyCloneable<T> extends Cloneable {
    public T clone();
}
Dann vereinfacht sich die Kopiermethode:
Java:
  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;
  }
 

Zurück
Oben