尝试使用Java中的构造函数创建对象的“副本”,但是我传入的内容会发生什么?

时间:2017-03-21 22:46:07

标签: java constructor reference

好的 - 标题没有多大意义。我提前道歉 - 我对一些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”,容器1是否会受到影响?我正在运行它来检查它的行为,但如果有人能解释它是如何工作的,那将非常感激。

2 个答案:

答案 0 :(得分:1)

请注意,这个答案是在你的编辑之前关于构造函数的性质,所以这些东西中的一些可能是无关紧要的,但概念仍然存在,所以除了添加你的情况之外我没有太多要改变下面第一个列表中的第4个项目符号点,因此通过对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()的返回值。
  • 以下是some techniques for deep copying generic Maps,如果您坚持使用通用Map接口,这可能会非常棘手。
  • 另外请不要忘记您可以在“更高”级别上复制。例如,如果您的容器有自己的“添加/插入”操作和他们自己的“获取”/迭代器操作,您可以不执行引擎盖下的内容并使用高级方法,这可以大大简化您的代码(完全构成示例),并删除对容器的实际实现细节的依赖:

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

    Fwiw,如果我的容器实现变得复杂,这是我可能采取的方法。

这里只需要处理一小部分事情。文档也是你的朋友,清楚地记录你的不变量和假设,如“修改此方法返回的地图将修改此容器”或“此构造函数创建其参数的深层副本”等。然后坚持实现中的那些(并测试!)。

答案 1 :(得分:0)

声明这样的对象不会影响初始对象。如果您声明了对象

SomeContainer container2 = container1;

然后当你修改container2时,它也会修改container1。