Java的传值是否意味着我的类不需要deepCopy函数?

时间:2014-09-08 17:27:41

标签: java multithreading user-interface swingworker

我正忙着让我的一些代码工作。代码启动SwingWorker并获取结果。我无法将数据传递给工作人员并从工作人员那里获取信息。

我想要传递的数据由我自己定义的类的对象组成。例如,我有一个ItemInventory对象。 Item对象基本上包含所有原始类型(名称,价格等),Inventory包含LinkedList Item个。

我无法完全记住导致我的理智检查的一系列事件,但作为一项完整性检查,我实施了Item.getDeepCopy(Item inItem)Inventory.getDeepCopy(Inventory)功能,以便我可以传递{{1 s和Item给我的工人。 这需要吗?

当我将数据传递到Inventory并从中获取数据时,我如何使用深层复制功能。假设我因点击按钮而启动了一名工作人员。在事件处理程序中,我首先获得我的类StringWorkerInventory的私有本地副本的深层副本,并将其传递给worker构造函数。 这是对的吗?我是否需要通过深层复印?我认为不是..

我之所以这样做是因为担心工作人员会尝试修改对工作者本身内对象的类引用,从而导致一些线程问题。但经过一些阅读和批判性思考之后,情况并非如此,因为java是按值传递的,因此传递给worker的内容不可能导致GUI组件数据发生变化。 这是正确的想法吗?

然后当工人完成时,它会调用我写的覆盖Item方法。这个方法在EDT上运行,所以我可以从我的GUI组件调用函数,即我调用done的函数。工作者调用此函数并将其WorkerDone(boolean result, Inventory outInv)Inventory的本地副本传递(而不是深层复制)回GUI。当GUI获取它时,它会执行深层复制并将其本地ItemInventory设置为此值。 这是否适用于深层复制?

修改:再多一点。

基本上我想将“一些数据”传递给worker,并允许它在没有链接到GUI组件的情况下处理它。当工人完成后,它将成功完成或不成功。如果成功,我想从工作人员“返回”数据并使用返回的数据更新我的本地副本。我不希望工人“触摸”GUI中的任何数据。

对于可变性。我希望能够在创建对象后更改对象内的数据。这就是我构建应用程序的方法。我想要的不是非可变对象来保持线程安全,我只是不希望线程交互。我想向工作人员传递一些数据,基本上“忘记我发送了它”然后当工人完成并调用GUI的Item方法时,GUI只是同意将其本地数据副本设置为返回对象的值,如果工作者说它成功了。

编辑2:

只是为了更清楚地理解短语传递和传递参考。当我看到传值时,我的想法。假设我想按价值传递一个苹果,为了做到这一点,我会把我的苹果放在一台克隆机上,它可以在各个方面完全克隆苹果并通过那个苹果。无论谁通过这个克隆的苹果可以做任何事情,没有一个影响我最初的苹果。

当我看到传递引用时,我想到的是,如果我想通过引用传递我的申请,我会记下我的苹果在纸上的位置,然后通过它。然后收到这张纸的人可以来到我的苹果所在地并咬一口。

所以我的困惑来自于“Java是按值传递”,如果是,那么为什么在操作传递给它的值时我不得不担心我的工作程序导致线程违规?

3 个答案:

答案 0 :(得分:3)

Java是按值传递的,但是当您传递一个对象时,您传递的是一个引用,而只是该引用的副本。两个引用,原始和副本仍然引用堆中的同一组值。

担心可能无法控制可能修改对象的代码是有效的,但您可以将该对象包装在另一个无法更改的对象中,或指定具有提取方法但不设置方法的接口。

如果您可以更新数据,并且更新显示数据的中途,那么让GUI拥有自己的数据副本会非常有用。如果你不担心这种不一致,你可能只想在gui代码和非gui代码之间共享相同的引用,以保持代码简单(假设你的类是线程安全的)。

答案 1 :(得分:0)

"通过价值"表示传递对象引用。原始参考的副本,对象数据的副本。

换句话说,您的所有被访者都会看到同一个对象(并且可以随意更改)。

这里有一篇来自Oracle Java文档的关于制作对象策略的好文章" immutable":

答案 2 :(得分:0)

“按值传递”和“按引用传递”描述函数参数如何在堆栈上传递。它们与堆上的对象可能发生或不发生的内容无关。假设我们用一些完全编写的编程语言编写代码:

def foo(x) :
    x = 5;
end

def bar() :
    a = 3;
    foo(a);
    print a;
end

功能栏()打印什么?答案取决于foo()中的参数x是按值传递还是按引用传递。在按值传递的语言中(例如,在Java中),当bar()调用foo(a)时,传递局部变量a的值。 foo()函数可以修改它自己的那个值的副本,但它不能修改调用者的局部变量a。

在传递引​​用语言中,传递调用方局部变量的地址。 foo中的x成为a in bar()的别名,赋值x = 5会更改变量a的值。

Java总是按值传递:Java函数永远不能永远修改其调用者的局部变量。

人们感到困惑的是,Java值可以是基本类型(int,double,char,...),也可以是对象引用。

public javaFoo(MyType x) {
    x.setFrobber(true);
}

public javaBar() {
    MyType mt = new MyType();
    foo(mt);
    System.out.println(mt.toString());
}

javaFoo()中的变量x是与javaBar()中的变量mt不同的变量,“pass-by-value”表示javaFoo()函数不能更改mt。 但是两个变量都引用同一个对象,而javaFoo()可以修改对象。