好的-标题没有太大意义。我预先表示歉意-我对某些Java概念还比较陌生:

我有一堂课,看起来有点像这样(简化):

public class SomeContainer {
    T someEntity;
    Map<String, Map<String, List<SomeOtherClass>>>> someCrazyMapping;
}


我有一个类型为SomeContainer的变量,我们称它为container1。
我想制作container2,它本质上是container1的精确副本,但是我将对container2的“疯狂映射”进行一些修改。

我尝试做的是创建container1的“副本”,如下所示:

SomeContainer container2 = new SomeContainer(container1.getSomeEntity(),  container1.getSomeCrazyMapping())


构造函数是@AllArgsConstructor-只是将值复制为this.someEntity = someEntity(etc.)

如果将条目放入container2的“ crazyMapping”中,container1是否会受到影响?我正在运行它来检查其行为,但是如果有人可以解释它的工作原理,将不胜感激。

最佳答案

请注意,此答案早于您对构造函数的性质的编辑,因此其中有些内容可能是多余的,但概念仍然存在,因此,除了添加您的情况是第四个项目符号之外,我在这里没有太多更改点在下面的第一个列表中,因此确实存在通过对container1进行更改来修改container2的可能性,并且您将希望对该地图进行浅表或深表复制,而不是存储对其的引用。

基本上,“ container1会发生什么”正是您告诉代码对container1所做的事情。幕后不会发生任何棘手的事情。

因此,无法从给出的信息中给出确切的答案,而是从这一行:

SomeContainer container2 = new SomeContainer(container1.getSomeEntity(),
                                             container1.getSomeCrazyMapping());


根据所显示的内容,我们能最好地告诉您,只要container1不会被“修改”(取决于您认为“修改”的内容):


您实施的getSomeEntity()不会修改container1,并且
您实施的getSomeCrazyMapping()不会修改container1,并且
您对该构造函数的实现不会以导致修改clear()的方式来修改您传入的参数(例如,通过在您通过的地图上调用container1或其他方式)。
您对该构造函数的实现不会造成您以后可以通过container1修改container2的情况,例如您可以直接在getSomeCrazyMapping()中返回地图,在container2中存储对其的引用,然后通过该引用对其进行修改。


我宽松地使用“修改”一词,因为它实际上取决于您的情况,您认为要进行“修改”的是什么,但是不,不会随机发生任何事情,您必须分析代码以查看是否明确修改了任何内容。



因此,为了帮助您保持对事物的仔细控制,您可以使用一些工具。以下是一些示例,您可以作为练习来弄清楚如何有效使用它们:


大多数地图都有浅层的“副本构造函数”,例如HashMap。对相同键和值对象的引用将存储在副本中,但至少将是不同的映射。
你有例如您可以在容器,键和值对象上实现的Object#clone。请注意,有些地图也实现了Cloneable,例如参见HashMap#clone
你有例如如果要以编程方式确保没有人在该方法返回的映射中添加/删除值,可以使用Collections#unmodifiableMap来包装getSomeCrazyMapping()的返回值。
如果您坚持使用通用的Map接口,那么这里是some techniques for deep copying generic Maps,这可能会很棘手。
同样不要忘记,您可以在“更高”级别上进行复制。例如,如果您的容器具有自己的“添加/插入”操作和自己的“获取” /迭代器操作,则无法执行高级操作,而是使用高级方法,这样可以大大简化代码(完全组成示例),并消除对容器实际实现细节的依赖:

public SomeContainer (SomeContainer other) {
    for (ExampleEntry entry : other.getEntries())
        this.addEntry(entry);
}


首先,如果我的容器实现变得越来越复杂,我可能会采用这种方法。


您只需在此处处理一小部分事情。文档也是您的朋友,清楚地记录您的不变式和假设,例如“修改此方法返回的映射将修改此容器”或“此构造函数创建其参数的深层副本”等。然后坚持执行您的实现(并进行测试!)。

10-07 20:01