在下面的代码中,我发现如果在参数中传递映射,使用putAll方法可能会导致问题。
public class Main {
public static void main(String...strings ) {
Etudiant e1=new Etudiant(5, "A");
Etudiant e2=new Etudiant(6, "B");
Map<Integer, Etudiant> map= new HashMap<>();
map.put(1, e1);
map.put(2, e2);
Map<Integer, Etudiant> map2= new HashMap<>();
map2.put(1,map.get(1));
map2.put(1,map.get(2));
changeMe(map2);
System.out.println(map.get(1));
Map<Integer, Etudiant> map3= new HashMap<>();
map3.putAll(map);
changeMe(map3);
System.out.println(map.get(1));
}
private static void changeMe(Map<Integer, Etudiant> etudiants) {
etudiants.get(1).name="K";
}
}
}以下是输出结果:
Etudiant [age=5, name=A]
Etudiant [age=5, name=K]你能解释一下区别吗?
为什么在使用putAll之后,对象会发生变化?
发布于 2018-11-13 21:59:31
详细说明了您的代码
Etudiant e1=new Etudiant(5, "A");
Etudiant e2=new Etudiant(6, "B");
Map<Integer, Etudiant> map= new HashMap<>();
map.put(1, e1);
map.put(2, e2);map现在包含{1=Etudiant(5, "A"), 2=Etudiant(6, "B")}
Map<Integer, Etudiant> map2= new HashMap<>();
map2.put(1,map.get(1));
map2.put(1,map.get(2));map2现在包含{1=Etudiant(6, "B")}
changeMe(map2);
System.out.println(map.get(1));Etudiant(6, "B")已被重命名为 Etudiant(6, "K"),因此:
map现在包含{1=Etudiant(5, "A"), 2=Etudiant(6, "K")}
map2现在包含{1=Etudiant(6, "K")}
上面印着:
Etudiant(5,A)
Map<Integer, Etudiant> map3= new HashMap<>();
map3.putAll(map);map3内容是map内容的副本,因此:
map3现在包含{1=Etudiant(5, "A"), 2=Etudiant(6, "K")}
changeMe(map3);
System.out.println(map.get(1));Etudiant(5, "A")已被重命名为 Etudiant(5, "K"),因此:
map现在包含{1=Etudiant(5, "K"), 2=Etudiant(6, "K")}
map2现在包含{1=Etudiant(6, "K")}
map3现在包含{1=Etudiant(5, "K"), 2=Etudiant(6, "K")}
上面印着:
Etudiant(5,"K")
代码的工作方式与您编写代码的方式完全一致。
通过添加一组打印语句可以很容易地看到上述所有内容,这是调试代码的一种方法。
public class Test {
public static void main(String[] args) {
Etudiant e1=new Etudiant(5, "A");
Etudiant e2=new Etudiant(6, "B");
Map<Integer, Etudiant> map= new HashMap<>();
map.put(1, e1);
map.put(2, e2);
System.out.println("map: " + map);
Map<Integer, Etudiant> map2= new HashMap<>();
map2.put(1,map.get(1));
map2.put(1,map.get(2));
System.out.println("map2: " + map2);
changeMe(map2);
System.out.println("map: " + map);
System.out.println("map2: " + map2);
System.out.println(map.get(1));
Map<Integer, Etudiant> map3= new HashMap<>();
map3.putAll(map);
System.out.println("map3: " + map3);
changeMe(map3);
System.out.println("map: " + map);
System.out.println("map2: " + map2);
System.out.println("map3: " + map3);
System.out.println(map.get(1));
}
private static void changeMe(Map<Integer, Etudiant> etudiants) {
System.out.print("Renamed " + etudiants.get(1));
etudiants.get(1).name="K";
System.out.println(" to " + etudiants.get(1));
}
}
class Etudiant {
int id;
String name;
Etudiant(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Etudiant(" + this.id + ", \"" + this.name + "\")";
}
}输出
map: {1=Etudiant(5, "A"), 2=Etudiant(6, "B")}
map2: {1=Etudiant(6, "B")}
Renamed Etudiant(6, "B") to Etudiant(6, "K")
map: {1=Etudiant(5, "A"), 2=Etudiant(6, "K")}
map2: {1=Etudiant(6, "K")}
Etudiant(5, "A")
map3: {1=Etudiant(5, "A"), 2=Etudiant(6, "K")}
Renamed Etudiant(5, "A") to Etudiant(5, "K")
map: {1=Etudiant(5, "K"), 2=Etudiant(6, "K")}
map2: {1=Etudiant(6, "K")}
map3: {1=Etudiant(5, "K"), 2=Etudiant(6, "K")}
Etudiant(5, "K")发布于 2018-11-13 21:53:22
因为在map2
Map<Integer, Etudiant> map2= new HashMap<>();
map2.put(1,map.get(1));
map2.put(1,map.get(2));您将覆盖第一个元素,因此映射如下:
[1, e2]因此,当您调用changeMe()时,它正在更改e2,而不是e1,所以当您打印e1时,它将保持不变。然后,当您调用putAll()时,它实际上将更改第一个元素,并且更改将被反映出来。
来自Map::putAll的文档
此调用的效果相当于在此映射上对指定映射中从键k到值v的每个映射调用一次
put(k, v)。
所以两者是等价的
将代码更改为:
Map<Integer, Etudiant> map2= new HashMap<>();
map2.put(1,map.get(1));
map2.put(2,map.get(2));你应该得到预期的结果
发布于 2018-11-13 21:48:52
putAll和一系列的put都将实现同样的结果。但是,根据Map实现,putAll有时可以更快一些。例如,如果对映射的写入需要获得一个锁,那么putAll可以获取该锁一次,并将其用于所有锁。或者,如果一个映射必须在写操作之间执行一些内部维护或记帐,它也可以优化这些维护或记帐。
如果您已经有了一个集合,那么它也是一个不错的一行程序,因此它比循环更少冗长。
https://stackoverflow.com/questions/53289969
复制相似问题