【问题标题】:Java is always pass by value so why am I getting reference when using Array.get(index)? [duplicate]Java 总是按值传递,为什么我在使用 Array.get(index) 时会得到引用? [复制]
【发布时间】:2020-02-25 10:15:38
【问题描述】:

我正在处理我的应用程序中的这个错误并看到一些非常奇怪的东西:

    selectedService = dataResponse.getServices().get(position);
    selectedService.setPrice(3000);
    dataResponse.getServices().get(position).getPrice(); // Returns 3000 which should be 0

get 方法不应该将对象复制到selectedService 吗?如果没有怎么复制?

【问题讨论】:

  • 传值。你在这里得到了对象的引用值。

标签: java android


【解决方案1】:

不,不应该。

Java 总是按值传递,但该值本身就是一个引用。因此,如果您调用更改该特定对象数据的方法,它会反映到从该特定对象检索数据的所有方法。

这个问题的一个可能的解决方案是创建immutable types。有些类已经实现了这一点,例如,java.time 包中的所有类都是不可变的。这些类的所有“设置器”都返回具有指定值集的实例的新副本。一个例子可能是LocalDate::plusDays


这里有一个小例子,说明传递值和传递引用之间的区别。

看看这段代码。

void main() {
    Dog myLittleDog = new Dog("Brutus");
    change(myLittleDog);
    System.out.println(myLittleDog.getName());
}

void change(Dog aDog) {
    aDog = new Dog("Jack");
}

这里发生了什么?我们将名为“Brutus”的狗传递给change 方法。在这种方法中,我们将 Brutus 替换为名为“Jack”的新 Dog。如果我们打印myLittleDog 的名字,他的名字是什么?会是“杰克”吗?
答案是否定的。对狗的引用的值被复制,并且可以在名称aDog 下的change 方法中使用。 myLittleDogaDog 都指的是内存中相同的实际狗对象。但是现在change 方法用new 对象重新分配aDog。此时,变量myLittleDogaDog 都指向不同的对象。一旦change 方法退出,变量aDog 将无法访问,Jack 将被垃圾回收。 myLittleDog 仍被称为“布鲁图斯”。

相反,如果 Java 是按引用传递的,情况就不会如此。那么重新分配aDog 也意味着重新分配myLittleDog

另见:What's the difference between passing by reference vs. passing by value?

但是为什么我的selectedService 还是变异了呢?

虽然引用的值在传递给方法时会被复制,但这并不意味着对象不能更改(即被修改)。假设我给你一份我家钥匙的副本。你进入我的房子,把沙发搬到厨房。然后如果我进入我的房子,我会看到沙发已经被移动了。引用值被复制,但每个访问引用对象(房子)的人都会看到对它的修改。

【讨论】:

  • 那么将对象复制到另一个对象并对其进行更改的唯一方法是使用传递的值创建一个新对象?有没有更少样板的更简单的方法?
  • 如果您想为某个对象设置价格,但又不想在另一个对象上反映出来,您必须复制一份。例如,这通常使用构建器模式来完成。
【解决方案2】:

selectedService 这里是一个引用变量,它指向你分配给它的任何对象。将 dataResponse.getServices().get(position) 分配给 selectedService 时,看起来好像您正在为它分配一个对象,但是,您实际上分配的是对原始对象的引用。

引用https://www.geeksforgeeks.org/clone-method-in-java-2/

与 C++ 不同,在 Java 中,如果我们使用赋值运算符,那么它将创建引用变量的副本,而不是对象

创建对象的副本

使用clone() 方法创建对象的副本,如

selectedService = (SelectedServiceClass) dataResponse.getServices().get(position).clone();

【讨论】:

  • 'clone()' 具有受保护的访问权限
  • stackoverflow.com/questions/16044887/… 我的错,如果你定义了自己的类并用公共方法覆盖它,你可以使用克隆,但它仍然是有风险的。我遇到了this,其中包含许多成功复制对象的方法
猜你喜欢
  • 1970-01-01
  • 2013-01-21
  • 2013-03-06
  • 2012-12-06
  • 1970-01-01
  • 2015-03-06
  • 1970-01-01
  • 2013-05-31
  • 2017-12-08
相关资源
最近更新 更多