为啥我无法获得对地图中某个值的引用? [复制]
Posted
技术标签:
【中文标题】为啥我无法获得对地图中某个值的引用? [复制]【英文标题】:Why cant I get a reference to a value in a map? [duplicate]为什么我无法获得对地图中某个值的引用? [复制] 【发布时间】:2018-11-08 06:26:59 【问题描述】:对于在大多数情况下(但有时不是)作为参考的所有内容以及容器,我感到非常困惑。考虑这段代码:
HashMap<Integer,String> x_map = new HashMap<>();
x_map.put(42,"foo");
String g = x_map.get(42);
g = "bar";
System.out.println(g.equalsIgnoreCase(x_map.get(42)));
为什么会打印false
?
我找到了正确的方法: How to update a value, given a key in a java hashmap?,但我完全迷失了为什么上面的内容不能按预期工作。此外,当地图中的对象相当大时,我希望能够只修改地图中一个值的单个成员,目前我不知道如何在不创建新实例并将其放入地图。
【问题讨论】:
因为您不会覆盖地图中的值。get
为您提供对该值的引用,然后您只需将该引用重新分配给其他值。如果您想在地图中添加新值,请使用x_map.put(42, "newValue");
。
变量在 Java 中是按值分配的。 g = x_map.get(42)
只是将映射中的 值 分配给变量 g
。如果您重新分配 g
,那么您将 g
重新指向不同的值。
@f1sh 如何覆盖地图中的值?
你 put
相同的值会有不同的东西。 IE。 x_map.put(42, "bar");
.
@user463035818 String
对象在 Java 中是不可变的。如果你想拥有一个可变字符串,你必须编写自己的类。
【参考方案1】:
@khelwood 在评论中给出了原因:
Java 中的变量是按值分配的。 g = x_map.get(42) 只是 将映射中的值赋给变量 g.如果你重新分配 g, 那么你将 g 重新指向一个不同的值。
如果不是String
,我在地图中放置了一些实际上可以修改的东西,那么它就可以正常工作:
public static class Test
public int x = 5;
然后……
HashMap<Integer,Test> x_map = new HashMap<>();
x_map.put(42,new Test());
Test g = x_map.get(42);
g.x = 12;
System.out.println((g.x == x_map.get(42).x) + " " + g.x + " " + x_map.get(42).x);
打印true 12 12
。
【讨论】:
【参考方案2】:按值传递
Java 是按值传递(请参阅Is Java “pass-by-reference” or “pass-by-value”?)。
这意味着当你这样做时
Person first = new Person("John");
Person second = first;
你有两个不同的变量,都指向内存中的实例new Person("John")
。但同样,这两个变量不同:
first ---|
|---> new Person("John")
second ---|
如果您操纵对象本身,则更改会反映到两个变量:
second.setName("Jane");
System.out.println(first.getName()); // Jane
现在的图表是:
first ---|
|---> new Person("John").setName("Jane")
second ---|
但是如果你改变一个变量指向的位置,它显然不会影响另一个变量,因为你没有触摸它们指向的对象:
second = new Person("Jane");
System.out.println(first.getName()); // John
在该语句之后,您有两个变量指向不同的对象:
first ---> new Person("John")
second ---> new Person("Jane")
说明
让我们将这些知识转移到您的代码中。你写道:
String g = x_map.get(42);
g = "bar";
并询问为什么 g = "bar"
没有不影响地图存储的内容。
如前所述,您只需更改变量g
指向的位置。您不操纵地图内的对象。先上图:
|---> x_map.get(42)
g ---|
"bar"
然后
x_map.get(42)
g ---|
|---> "bar"
解决方案
如果你想改变对象,你需要直接操作它而不是仅仅改变变量引用。喜欢first.setName("Jane")
。然而,在 Java 中String
s 是不可变的。这意味着无法操纵String
。 String#replace
之类的方法不会操作原始字符串,它们总是会创建一个新的 String
对象并保持旧的对象不变。
因此,为了更改地图存储的内容,他们键入 42
,您只需使用 Map#put
方法:
x_map.put(42, "bar");
这会将 x_map
为密钥 42
存储的内容更改为 "bar"
。
【讨论】:
我实际上是在修改了存储在一般地图中的对象之后,字符串有点特殊是一个非常不幸的巧合。所以我想如果我有一个HashMap<Integer,SomeClass> map;
那么SomeClass g = map.get(42); g.setSomeProperty("asdf");
会按预期工作。
@user463035818 是的,没错。因为setSomeProperty
直接修改了对象。而不是仅仅改变g
指向的位置。
感谢您的解释。我不得不承认,我对收到我的问题的方式感到有些惊讶。我一直认为 C++ 角对新手来说很难,但在这里我得到了很多反对意见,却不知道这个问题有什么问题(除了像很多新手一样,这是反对反对意见的理由吗?)。没关系,再次感谢您的详细解释
@user463035818 好吧。否决票可能来自您没有进行足够的研究。由于this SO 线程回答了这个问题。所以从技术上讲,它是重复的。但是,如果您问我,如果不知道正确的术语以及您观察的原因,您将无法真正找到该线程。因此,由于minimal reproducible example 的详细解释,你有我的赞成票。【参考方案3】:
因为您没有更新 x_map 中 42 键的值。 为此你应该这样做
X_map.put(42, g)
【讨论】:
以上是关于为啥我无法获得对地图中某个值的引用? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为啥即使我能够获得对我试图滚动到的元素的引用,scrollIntoView 在 Vue 3 中也不起作用
为啥对 Python 值的引用(即函数参数)存储在 CPython 的堆栈(帧)中?