好的-标题没有太大意义。我预先表示歉意-我对某些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 Map
s,这可能会很棘手。同样不要忘记,您可以在“更高”级别上进行复制。例如,如果您的容器具有自己的“添加/插入”操作和自己的“获取” /迭代器操作,则无法执行高级操作,而是使用高级方法,这样可以大大简化代码(完全组成示例),并消除对容器实际实现细节的依赖:
public SomeContainer (SomeContainer other) {
for (ExampleEntry entry : other.getEntries())
this.addEntry(entry);
}
首先,如果我的容器实现变得越来越复杂,我可能会采用这种方法。
您只需在此处处理一小部分事情。文档也是您的朋友,清楚地记录您的不变式和假设,例如“修改此方法返回的映射将修改此容器”或“此构造函数创建其参数的深层副本”等。然后坚持执行您的实现(并进行测试!)。