首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >循环中的java.util.Map.putAll(Map<>)和java.util.Map.put(Integer,Object)有什么区别?

循环中的java.util.Map.putAll(Map<>)和java.util.Map.put(Integer,Object)有什么区别?
EN

Stack Overflow用户
提问于 2018-11-13 21:44:16
回答 3查看 272关注 0票数 0

在下面的代码中,我发现如果在参数中传递映射,使用putAll方法可能会导致问题。

代码语言:javascript
复制
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";
    }
}
}

以下是输出结果:

代码语言:javascript
复制
Etudiant [age=5, name=A]
Etudiant [age=5, name=K]

你能解释一下区别吗?

为什么在使用putAll之后,对象会发生变化?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-11-13 21:59:31

详细说明了您的代码

代码语言:javascript
复制
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")}

代码语言:javascript
复制
Map<Integer, Etudiant> map2= new HashMap<>();
map2.put(1,map.get(1));
map2.put(1,map.get(2));

map2现在包含{1=Etudiant(6, "B")}

代码语言:javascript
复制
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)

代码语言:javascript
复制
Map<Integer, Etudiant> map3= new HashMap<>();
map3.putAll(map);

map3内容是map内容的副本,因此:

map3现在包含{1=Etudiant(5, "A"), 2=Etudiant(6, "K")}

代码语言:javascript
复制
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")

代码的工作方式与您编写代码的方式完全一致。

通过添加一组打印语句可以很容易地看到上述所有内容,这是调试代码的一种方法。

代码语言:javascript
复制
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 + "\")";
    }
}

输出

代码语言:javascript
复制
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")
票数 6
EN

Stack Overflow用户

发布于 2018-11-13 21:53:22

因为在map2

代码语言:javascript
复制
Map<Integer, Etudiant> map2= new HashMap<>();
map2.put(1,map.get(1));
map2.put(1,map.get(2));

您将覆盖第一个元素,因此映射如下:

代码语言:javascript
复制
[1, e2]

因此,当您调用changeMe()时,它正在更改e2,而不是e1,所以当您打印e1时,它将保持不变。然后,当您调用putAll()时,它实际上将更改第一个元素,并且更改将被反映出来。

来自Map::putAll的文档

此调用的效果相当于在此映射上对指定映射中从键k到值v的每个映射调用一次put(k, v)

所以两者是等价的

将代码更改为:

代码语言:javascript
复制
Map<Integer, Etudiant> map2= new HashMap<>();
map2.put(1,map.get(1));
map2.put(2,map.get(2));

你应该得到预期的结果

票数 3
EN

Stack Overflow用户

发布于 2018-11-13 21:48:52

putAll和一系列的put都将实现同样的结果。但是,根据Map实现,putAll有时可以更快一些。例如,如果对映射的写入需要获得一个锁,那么putAll可以获取该锁一次,并将其用于所有锁。或者,如果一个映射必须在写操作之间执行一些内部维护或记帐,它也可以优化这些维护或记帐。

如果您已经有了一个集合,那么它也是一个不错的一行程序,因此它比循环更少冗长。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53289969

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档