在Java中引用对象

3

我对Java中的对象引用有疑问。它总是通过引用将其对象发送到函数,这意味着如果您在发送的函数中修改了它们,它们将以修改后的形式返回。

解决此问题的方法是在发送之前复制对象。但是,我必须在对象类中创建一个复制函数吗?还是有其他选择?谢谢。


7
它总是通过引用将其对象发送给函数。不,它发送的是引用值的副本。 - Sotirios Delimanolis
@BLuFeNiX 对象不是通过引用传递的。 - Sotirios Delimanolis
1
@BLuFeNiX 你应该阅读:https://dev59.com/EXVD5IYBdhLWcg3wQJOT - Sotirios Delimanolis
2
@BLuFeNiX 不,它们不一样。传递引用意味着您可以更改调用上下文中的局部变量或字段的值,因为您传递了对这些内存位置的引用。 (而不是指向具有这些字段的对象,那是“不算”的。)这是在Java中无法做到的,而在C、C++和我认为PHP中很容易实现。如果有助于澄清问题,则传递引用意味着您必须能够将lvalue传递给被调用的函数。在Java中,您只能传递(可能可变的)rvalues。 - millimoose
1
每天都有新的东西可以学习。 - BLuFeNiX
显示剩余13条评论
4个回答

3
我通常会为这种情况添加一个拷贝构造函数,像这样:
public class MyObject {
    //members


    public MyObject(MyObject objectToCopy) {
       this.member = objectToCopy.member;
       //...
    }
}

然后您只需使用简单的一行代码创建一个新对象。
public void DoWork(MyObject object) {
    MyObject copy = new MyObject(object);
    //do stuff
}

1
最佳实践不是实现克隆吗? - danieln
1
-1:很抱歉,但这不是复制/克隆对象的正确方法。更多信息:Java:深度克隆/复制实例的推荐解决方案 - Luiggi Mendoza
这会导致更复杂的对象代码非常混乱。我不建议像这样复制。 - Vegard
@Vengard 对于复杂对象,我可能会同意你的看法,但是用大锤子敲钉子是愚蠢的。简单对象可以使用更有效的简单方法,而不是反射。 - Matthew Cox
@LuiggiMendoza 我会对你说与我对Vengard所说的一样...此外,任何反射的使用都会带来更高的性能成本,这一点不应被忽视。 - Matthew Cox
显示剩余2条评论

3

Java始终是按值传递。你所描述的是将对象引用按值传递。

这里有一个关键区别。你不是传递对象引用,因此引用链接在你给参数分配新实例时就被断开了。只要引用值保持不变,在修改传入对象的内容后,当你返回到调用者时,修改都会持久化。另一个关键区别是引用值可以为null……但null并不是一个对象——那么你如何引用不存在的对象呢?

如果你想创建一个新对象,你需要复制现有对象。这个复制应该在方法内完成,以确保操作是一致的。

对于简单对象(类层次浅的对象,就像下面的例子),通常可以使用基本的复制构造函数:

class Album {
  private String title;
  private String artist;

  public Album(Album copy) {
    this.title = copy.title;
    this.artist = copy.artist;  
  }
}

这将允许您在方法内复制对象:
public void copyAlbum(Album album) {
    album = new Album(album); // Clone the album passed in
}

对于更复杂的对象图,您可能想要使用诸如OrikaDozer等库来精确创建对象的深层副本。 这个问题提供了一些有用的Java对象复制建议。


+1 for the first sentence. - Fritz
1
你的答案非常不错,直到你写了那个克隆对象的例子... - Luiggi Mendoza
请定义简单类(不是对象,因为对象是类的实例)。 - Luiggi Mendoza
啊,关于复制构造函数的危险的古老战争!我不同意,手动复制对象是确保正确完成的最安全的方法。克隆工具在某些情况下很有帮助,但必须使用正确的工具来完成工作。我看到过更多使用配置错误的Dozer进行对象克隆的糟糕示例,而传统的复制构造函数方法则很少出现这种情况。 - seanhodges

1

你需要为每个对象自己创建一个复制构造函数。原因很简单:如果A引用B并且你想要复制A,你会复制对B的引用还是整个被引用的B对象?这个问题必须针对每种情况单独回答,因此没有通用解决方案。


1

确实,您发送的是对象,并且对所引用的对象进行更改。在Java中没有简单的“本地”方法来复制对象,但是您可以使用Dozer等框架来复制对象:

http://dozer.sourceforge.net/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接