Java是按值传递还是按引用传递?

20

我有一个HashMap:

private HashMap<String, Integer> cardNumberAndCode_ = new HashMap<String, Integer>();

之后我执行了这个操作:

Integer balance = cardNumberBalance_.get(cardNumber);
System.out.println(balance);
balance = 10;
Integer newBalance = cardNumberBalance_.get(cardNumber);
System.out.println(newBalance);

首先它打印了1000,第二次打印1000时,值没有改变。为什么Java按值返回整数而不是按引用返回?


2
整数是一个引用,你似乎想要一个引用的引用,而Java不支持这种操作。 - Peter Lawrey
4个回答

19

get方法返回存储整数的引用的副本...

将新值赋给存储此副本的变量以指向值10不会更改地图中的引用。

如果你能够执行balance.setValue(10),那就可以解决此问题,但由于Integer是一个不可变类,所以这是不可能的。

如果要在映射中生效更改,您必须将余额包装在一个(可变)类中:

class Balance {
    int balance;
    ...
}

Balance balance = cardNumberBalance_.get(cardNumber);
System.out.println(balance.getBalance());
balance.setBalance(10);
Balance newBalance = cardNumberBalance_.get(cardNumber);
System.out.println(newBalance.getBalance());

但你可能想要像这样做:

cardNumberBalance_.put(cardNumber, 10);

2
你不能这样做... 你必须将余额包装在一个单独的可变类中... 还要注意 Integer 是一个不可变类。 - aioobe
@aioobe - 你会说一个方法返回“true的副本”还是“42的副本”吗?那么,一个返回引用的方法也不会返回“副本”,它只会返回该引用。 - Stephen C
啊,好的。这取决于你使用“引用”一词是指它所包含的值还是变量。但我明白你的意思。 - aioobe

2
整数变量包含对对象的引用。整数对象是不可变的,您无法更改它。当您执行操作时,如加法或减法,将创建一个新的整数对象。
balance = 10; // replace the previous Integer reference with a different one.

这个问题的解决方案是使用常规方法:
cardNumberBalance_.put(cardNumber, 10);

一个不太常用的替代方法是使用AtomicInteger或使用自己的MutableInteger。

private final Map<String, AtomicInteger> cardNumberAndCode_ = new HashMap<String, AtomicInteger>();

AtomicInteger balance = cardNumberBalance_.get(cardNumber);
balance.set(10);

4
对象本身永远不会被传递。通过值传递(或返回)引用。这是一个微妙但重要的区别。 - Jon Skeet
@Jon Skeet,措辞不正确。我已经尝试修正了它。 - Peter Lawrey
1
好多了,谢谢。如果我的投票反对看起来有点严厉,我很抱歉,但是我已经反对使用“按引用传递”这个术语来描述Java多年了 :) - Jon Skeet
@Jon Skeet,我完全理解。;) - Peter Lawrey

1

赋值的结果

balance = 10;

创建一个新的 Integer 实例,其值为 10,并将其引用分配给变量 balance。这并不会改变从映射中获取的对象,即存储在映射中的对象保持不变。

如果需要更改余额的值,则必须将其包装在可变类中,就像aioobe描述的那样。


1

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