我创建了一个具有返回地图的getter的对象。当我调用getter并从调用对象更改地图时,为什么它会影响原始地图。即使它被宣布为最终的。为什么会这样呢?
1>是否因为getter只返回对象引用而不是返回一个map对象? 2>这也会出现在列表中吗?
下面的代码只是例如不完美的代码。
public class Worker{
private final Map<String, String> work;
public MatcherManager(Map<String, String> input) {
checkNotNull(input, "Input map not found");
his.workExperienceMatcher = input;
}
public Map<String, String> getWork() {
return work;
}
答案 0 :(得分:3)
你自己说 - “1&gt;是不是因为getter只返回对象引用而不是返回一个map对象?”
是的,在Java中,一切都是使用对象的引用来操纵的
。你正在获得地图的参考,改变它。即使你已经宣布它为“最终”,最终和不变性是两个不同的东西..最终意味着,“你不能改变参考”,不变性意味着 - “你不能改变对象的价值“。通过将非原始变量声明为final,您会说 - “我不会将此引用指向其他任何内容。但我可以更改我的引用所指向的对象的属性。” 。对于原语,你不能改变最终变量的值。不可变性不是Java中的内置功能。通过仅提供“公共吸气剂”而非提供者,可以实现不变性。不可靠性阻止改变对象的价值。最终阻止改变参考。记住 - “在Java引用中按值传递”。
如果您需要不可修改/不可变列表,可以使用
Collections.unmodifiableList
答案 1 :(得分:2)
通过返回相同的地图,外部世界现在获得一个句柄(换句话说,引用)来改变地图。
如果您不希望出现这种行为,则可以返回另一个引用:
public Map<String, String> getWork() {
return new HashMap<String, String>(work);
}
邪恶的,外面的世界现在只能改变这个新的引用 - 它对底层的work
地图没有影响。
是的,同样的理论适用于其他集合类,例如列表和集合。
答案 2 :(得分:2)
您将返回一个对象引用,该引用指向与原始地图相同的内存地址。因此,当您更改地图中的特定值时,您将更新两个地图指向的值。对于列表也是如此。声明为final的地图不能为其分配新地图,但可以更新最终地图中的值。
答案 3 :(得分:1)
是的,传递的是对原始对象的引用。因此,您对返回的对象所做的更改会影响原始对象。
Java使用'按值传递'机制。但是,对于对象,传递的是对象的引用的副本。因此,通过返回的引用所做的更改会影响原始对象。然而,当涉及到原语时,传递的是真正的副本,因此您对原语的更改不会影响原始。
答案 4 :(得分:1)
1&gt;是否因为getter只返回对象引用而不是返回一个map对象? 是的,最终只装饰物理地址。它不关心价值。所以你可以改变参考的价值。 2&gt;这也会出现在列表中吗? 是的,这是相同的原则。