Java HashMap 对象引用混淆

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24486318/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:31:02  来源:igfitidea点击:

HashMap Object reference confusion

javareferencehashmap

提问by user3789587

Hello I'll go straight into the problem. I know that in HashMaps in java the valueSet stores REFERENCE, that means that if I change that reference the specific value of that key should change too since both refer to the same object.

你好,我会直接进入问题。我知道在 java 的 HashMaps 中,valueSet 存储 REFERENCE,这意味着如果我更改该引用,该键的特定值也应该更改,因为两者都引用同一个对象。

But I had some problems with my application so I tried to debug it to see how HashMap works practically. So I coded this mini proggram:

但是我的应用程序遇到了一些问题,所以我尝试调试它以查看 HashMap 的实际工作方式。所以我编写了这个小程序:

class Test
{
    private final static HashMap<Integer, String> test = new HashMap<>();

    public static void main(String[] args)
    {
        String s = "String";
        test.put(1, s);
        test.put(2, "2");
        test.put(3, "3");
        s = "1";
        for (Integer i : test.keySet())
            System.out.println("Key: " + i + ", Value: " + test.get(i));
        }
    }
}

The output is:

输出是:

Key: 1, Value: String
Key: 2, Value: 2
Key: 3, Value: 3

Whats wrong here? I changed the value of String s right before Iterating the HashMap and it still shows the old value. That shows to me that HashMap DOES NOT work with object reference?

这里有什么问题?我在迭代 HashMap 之前更改了 String 的值,它仍然显示旧值。这向我表明 HashMap 不适用于对象引用?

Where am I wrong in here?

我哪里错了?

Thanks for your time.

谢谢你的时间。

EDIT:

编辑:

Tried with a test Object and the results are even more confusing since it seems like it WORKS for reference but not for Immutable objects as our fellow mate said:

尝试使用测试对象,结果更令人困惑,因为它似乎适用于参考,但不适用于不可变对象,正如我们的伙伴所说:

class Test 
{
    private final static HashMap<Integer, TestObject> test = new HashMap<>();

    public static void main(String[] args)
    {
        TestObject to = new TestObject();
        test.put(1, to);
        test.put(2, new TestObject());
        test.put(3, new TestObject());
        to.setValue(16);
        for (Integer i : test.keySet())
            System.out.println("Key: " + i + ", Value: " + test.get(i).getValue());
    }

    public static class TestObject
    {
        private int value;

        public void setValue(int val)
        {
            value = val;
        }

        public int getValue()
        {
            return value;
        }
    }
}

this prints

这打印

Key: 1, Value: 16
Key: 2, Value: 0
Key: 3, Value: 0

采纳答案by Ankit Katiyar

Their is nothing wrong with the HashMap. You are mis-understanding the concept of String object.

他们的 HashMap 没有错。您误解了 String 对象的概念。

Stringis immutable. That means how many time you make changes in string object it will create a new object and provide the reference to variable.

字符串是不可变的。这意味着您对字符串对象进行多少次更改,它将创建一个新对象并提供对变量的引用。

Just test this small Code

只需测试这个小代码

String s="String";
System.out.println("Old-"+s.hashCode());
s="New String";
System.out.println("New-"+s.hashCode());

Output

输出

Old--1808118735
New-1745736401

Here you can see as you made change to String variable it's hascode is changed that means a new object created in String Pool and new reference to the variable.

在这里您可以看到,当您对 String 变量进行更改时,它的 hascode 已更改,这意味着在 String Pool 中创建了一个新对象以及对该变量的新引用。

I your case

我你的情况

HashMap<Integer, String> test=new HashMap<Integer, String>();
String s = "String";
System.out.println("Adding with -"+s.hashCode());
test.put(1, s);
test.put(2, "2");
test.put(3, "3");
s = "1";
System.out.println("Modified s-"+s.hashCode());
for (Integer i : test.keySet())
    System.out.println("Key: " + i+ ", Value: " + test.get(i)+"  "+test.get(i).hashCode());
}

Write it like this and see the magic output.

像这样写,看看神奇的输出。

Adding with --1808118735
Modified s-49
Key: 1, Value: String  -1808118735
Key: 2, Value: 2  50
Key: 3, Value: 3  51

HashMap still contains the old string reference.

HashMap 仍然包含旧的字符串引用。

回答by Jon Skeet

I changed the value of String s

我改变了 String 的值

Yes, you changed the value of s. That's allyou changed. The map still contains the previousvalue of the variable. You haven't changed the meaning of that value.

是的,您更改了 的值s。这就是你改变的全部。映射仍包含变量的先前值。您没有更改该值的含义。

We can simplify your example to just plain string variables:

我们可以将您的示例简化为纯字符串变量:

String x = "hello";
String y = x;
x = "goodbye";
System.out.println(y); // "hello"

The assignment (y = x) just copies the current value of xinto y. That value is a reference, but it doesn't "know" where it came from - its only relation to the variable xis that it happened to be the value of xat the time of the assignment. When you later change the value of x, that doesn't change the value of y.

赋值 ( y = x) 只是将 的当前值复制xy。该值是一个引用,但它不“知道”它来自哪里——它与变量的唯一关系x是它恰好是x赋值时的值。当您稍后更改 的值时x,不会更改 的值y

The exact same thing happens in Map.put- the current valueof the variable is used as the key. Changing the variable's value later doesn't affect the content of the map.

完全相同的事情发生在Map.put-变量的当前值用作键。稍后更改变量的值不会影响地图的内容。

About mutability

关于可变性

None of the statements above depend on the mutability of the type in question. For example, you can see the exactsame behaviour with StringBuilder:

上面的语句都不依赖于所讨论类型的可变性。例如,您可以使用以下命令查看完全相同的行为StringBuilder

StringBuilder x = new StringBuilder("hello");
StringBuilder y = x;
x = new StringBuilder("goodbye");
System.out.println(y); // "hello"

You'll only see a change in behaviour if you change your code more drastically:

如果您更彻底地更改代码,您只会看到行为的变化:

StringBuilder x = new StringBuilder("hello");
StringBuilder y = x;
x.append(" world");
System.out.println(y); // "hello world"

Compare these statements:

比较这些陈述:

// First version
x = new StringBuilder("goodbye");

// Second version
x.append(" world");

The first version changes the value of x. After the assignment, xhas a different value: a reference which refers to a different object. It's like moving to a different house: my home address is not the same as it was.

第一个版本更改了 的值x。赋值后,x有一个不同的值:一个引用不同对象的引用。这就像搬到不同的房子:我的家庭地址和以前不一样。

The second version does not change the value of x. It changes the content of the object that the value of xrefers to. That's like painting the front door of my house: the address is still the same (it refers to the same house), it's just that some aspect of that house has changed.

第二个版本不会改变 的值x。它改变了值x所指对象的内容。这就像粉刷我家的前门:地址还是一样(指的是同一栋房子),只是那栋房子的某些方面发生了变化。

回答by Abhishek Mishra

As per your code Sreference pointing to object "String". And hashMap key i.e. "1" is also pointing to object"String" once test.put(1, s);get executed,now you change spointing object ,means after you change the value of s to 1 ,now s is pointing to object"1" and key "1" of hashmap is still pointing to object "String".

根据您的代码S引用指向对象“ String”。并且 hashMap 键即“ 1”也指向对象“String”一旦 test.put(1, s); 得到执行,现在你改变s指向对象,意味着在你将s的值更改为1之后,现在s指向对象“1”并且hashmap的键“1”仍然指向对象“String”。

回答by Saif

Let me give u an example: Here the real objects are like any place say Homeand reference are their address. Now you are making a listof addresses it can be HashMap or List of anything.

让我给你举个例子:这里的真实对象就像任何地方一样,比如Home和 reference 是它们的地址。现在您正在制作一个地址列表,它可以是 HashMap 或任何内容的列表。

Assume you have a piece of paper and address of Home1written on it. Now you give this paper to you friend to make a list and he copy this address in his list. Now you throw you parer and pick another paper which contain address of Home2. Now if you deliver something it will go to Home2and if you friend deliver something according to the list it will go to Home1.

假设你有一张纸,上面写着Home1 的地址。现在你把这张纸给你的朋友列一个清单,他把这个地址复制到他的清单中。现在你扔掉你的 parer 并选择另一篇包含Home2地址的论文。现在,如果你送东西,它会转到Home2,如果你的朋友根据列表送东西,它会转到Home1

That's why when you change the value of s

这就是为什么当你改变的价值 s

 s = "1";

it change the value of sbut doesn't change the value of reference inside the list.

它会改变 的值s但不会改变列表中引用的值。

**Actually you are not changing the value of the object that pointed by syou are telling sto point another object.**

**其实你不改变这种指向的对象的值,s你告诉s指向另一个对象。**