[英]Copying HashMap to another HashMap
我在將HashMap A復制到HashMap B時遇到問題。B始終與A相同。我的想法是僅使用HashMaps制作小型圖塊游戲。
Map<Point,Tile> A = new HashMap<Point,Tile>();
HashMap有2件事。 一個point(key)和一個tile對象,這是我制作的另一個類。 Tile接受兩個整數和一個字符串。 (新的Tile(x,y,string))。 前兩個整數定義點x和y,字符串告訴它的“ OFF”還是“ ON”。
我首先要做的是用2 * 2元素填充HashMapA。
for(int i=0; i<2;i++){
for(int j=0; j<2;j++){
Tile t = new Tile(i, j, "OFF");
A.put(new Point(i,j), t);
}
}
然后,通過在構造函數中添加A,將HashMap A復制到HashMapB。 我的想法是,我可以通過在構造函數中使用HashMap B返回默認的HashMapA。
Map<Point,Tile> B = new HashMap<Point,Tile>(A);
然后我將圖塊(1,1)更改為“ ON”
Tile t2 = A.get(new Point(1,1));
t2.setS("ON");
我的瓷磚之一現在處於“開啟”狀態。 現在,我想將板重置為原始狀態(在填充階段之后)。 我清除HashMap A並使用HashMap B作為構造函數制作一個新的HashMap。
A.clear();
A = new HashMap<Point,Tile>(B);
但是,當我在HashMap A上將tile(1,1)更改為ON時,它也更新了HashMapB。 我以為使用構造函數創建新的HashMap會對其進行新的復制,但似乎不起作用。
奇怪的是
Map<Point,String> A = new HashMap<Point,String>();
會工作,但不會
Map<Point,Tile> A = new HashMap<Point,Tile>();
我想以某種方式獲得HashMap A的原始內容,而無需嘗試再次遍歷元素。
這是我的主要課程代碼
package main;
import java.awt.Point;
import java.util.HashMap;
import java.util.Map;
import model.Tile;
public class Test {
public static void main(String[] args) {
//list1
Map<Point,Tile> A = new HashMap<Point,Tile>();
//Populating map
for(int i=0; i<2;i++){
for(int j=0; j<2;j++){
Tile t = new Tile(i, j, "OFF");
A.put(new Point(i,j), t);
}
}
//copying list1 to list2
Map<Point,Tile> B = new HashMap<Point,Tile>(A);
//Change tile on 1,1 to ON
Tile t2 = A.get(new Point(1,1));
t2.setS("ON");
for(int i=0; i<2;i++){
for(int j=0; j<2;j++){
Tile tTemp = A.get(new Point(i,j));
System.out.println(i+" "+j+" "+tTemp.getS());
}
}
//Reseting tiles
//clear first list
A.clear();
System.out.println("");
//copy second list to first list
A = new HashMap<Point,Tile>(B);
for(int i=0; i<2;i++){
for(int j=0; j<2;j++){
Tile tTemp = A.get(new Point(i,j));
System.out.println(i+" "+j+" "+tTemp.getS());
}
}
}
}
這是瓷磚課
package main;
public class Tile {
public int x,y;
public String s;
public Tile(int x1, int y1, String st){
x=x1;
y=y1;
s=st;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
}
這是清除HashMap A之前要打印的內容
0 0 OFF
0 1 OFF
1 0 OFF
1 1 ON
這是清除HashMap A然后將B復制到它之后要打印的內容。
0 0 OFF
0 1 OFF
1 0 OFF
1 1 ON
沒有不同。
您需要通過克隆 Tile
對象來深度復制 HashMap
。
默認情況下, HashMap
構造函數正在執行淺表復制 。 它只是從傳入的Map
復制值,該值適用於Map
元 , String
(和其他不可變對象),但不適用於對Object
類型的引用,因為復制的引用將指向相同的原始對象,因此稍后對其進行修改。
因此,要解決此問題,只需將深度復制方法實現為
public Map<Point, Tile> getDeepCopy(Map<Point, Tile> source) {
Map<Point, Tile> copy = new HashMap<Point, Tile>();
for (Map.Entry<Point, Tile> entry : source.entrySet())
copy.put(entry.getKey(), entry.getValue().clone());
return copy;
}
並使您的Tile
類實現Cloneable
並重寫 clone()
方法為
public class Tile implements Cloneable {
// other implementation
public Tile clone() throws CloneNotSupportedException {
return (Tile) super.clone();
}
}
在您使用Point
的方式上,我也沒有看到也需要clone()
,但是如果您也想對其進行深克隆,只需將其修改為上方的Tile
。
但是,當我在HashMap A上將tile(1,1)更改為ON時,它也更新了HashMapB。
當你寫:
Tile t2 = A.get(new Point(1,1));
t2.setS("ON");
您沒有更改任何一張地圖。 這些地圖僅引用Point
對象和Tile
對象。 它們具有相同的引用-復制地圖不會在其中克隆對象。
因此,當您更改其中一個對象的內容時,無論使用哪種地圖導航到該對象,都將看到該更改。
換句話說,請考慮這種情況:
喬會看到紅色的前門,是嗎? 這里完全一樣。
如果將Point
和Tile
類設置為不可變的,這將不是問題-因為您將無法更改現有對象的內容。 那時,復制引用和克隆對象之間沒有什么特別有意義的區別。 您最終將編寫如下內容:
Point p = new Point(1, 1);
Tile t2 = A.get(p);
t2 = t2.withS("ON"); // This would return a reference to a new object
A.put(t2);
Map<Point,Tile> B = new HashMap<Point,Tile>(A);
制作您的A
地圖的淺表副本。 它不會創建Point
和Tile
值的副本。 它使用與原始地圖中相同的參考。 因此,當你在改變一個瓷磚B
圖中,相同的瓷磚在改變A
地圖,反之亦然。
Map<Point,String> A = new HashMap<Point,String>();
因為String是不可變的,所以可以工作,因此與Tile
實例不同,您無法更改String
的狀態。
要創建A的深層副本,您必須遍歷A的條目,創建每個鍵和值的副本(假設Point鍵和Tile值都是可變的-如果Point不可變,則足以創建Tile值的副本),然后將副本放入B映射中。
Map<Point,Tile> B = new HashMap<Point,Tile>(A);
在需要深拷貝時進行淺拷貝。 您必須手動實現深層復制,或者使用某些庫來為您完成。 像這個:
在這里使用此實用程序類執行深度克隆。
//copying list1 to list2
Map<Point,Tile> B = DeepCopy.deepCopy(original)(A);
實用類:
public final class DeepClone {
private DeepClone(){}
public static <X> X deepClone(final X input) {
if (input == null) {
return input;
} else if (input instanceof Map<?, ?>) {
return (X) deepCloneMap((Map<?, ?>) input);
} else if (input instanceof Collection<?>) {
return (X) deepCloneCollection((Collection<?>) input);
} else if (input instanceof Object[]) {
return (X) deepCloneObjectArray((Object[]) input);
} else if (input.getClass().isArray()) {
return (X) clonePrimitiveArray((Object) input);
}
return input;
}
private static Object clonePrimitiveArray(final Object input) {
final int length = Array.getLength(input);
final Object copy = Array.newInstance(input.getClass().getComponentType(), length);
// deep clone not necessary, primitives are immutable
System.arraycopy(input, 0, copy, 0, length);
return copy;
}
private static <E> E[] deepCloneObjectArray(final E[] input) {
final E[] clone = (E[]) Array.newInstance(input.getClass().getComponentType(), input.length);
for (int i = 0; i < input.length; i++) {
clone[i] = deepClone(input[i]);
}
return clone;
}
private static <E> Collection<E> deepCloneCollection(final Collection<E> input) {
Collection<E> clone;
// this is of course far from comprehensive. extend this as needed
if (input instanceof LinkedList<?>) {
clone = new LinkedList<E>();
} else if (input instanceof SortedSet<?>) {
clone = new TreeSet<E>();
} else if (input instanceof Set) {
clone = new HashSet<E>();
} else {
clone = new ArrayList<E>();
}
for (E item : input) {
clone.add(deepClone(item));
}
return clone;
}
private static <K, V> Map<K, V> deepCloneMap(final Map<K, V> map) {
Map<K, V> clone;
// this is of course far from comprehensive. extend this as needed
if (map instanceof LinkedHashMap<?, ?>) {
clone = new LinkedHashMap<K, V>();
} else if (map instanceof TreeMap<?, ?>) {
clone = new TreeMap<K, V>();
} else {
clone = new HashMap<K, V>();
}
for (Entry<K, V> entry : map.entrySet()) {
clone.put(deepClone(entry.getKey()), deepClone(entry.getValue()));
}
return clone;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.