【问题标题】:Storing multiple type objects in HashMap and retrieving them在 HashMap 中存储多个类型对象并检索它们
【发布时间】:2015-10-01 11:19:50
【问题描述】:

在使用 Object 作为类型时,我很难理解 HashMap。

在这里,我创建了两个对象,一个字符串和一个整数,并为其赋值。然后我将这些对象添加到 HashMap。然后更改字符串和整数对象的值。但是当尝试使用HashMap.get() 引用它们时,它会显示原始值。

我假设在将值放在 HashMap 上时,会以某种方式在 HashMap 实例中创建一个新的未更改对象,而不是链接底​​层的原始对象?

代码如下:

import java.util.HashMap;
import java.util.Map;
public class Test1 {
    //Create objects
    static int integ=1;
    static String strng="Hi";
    //Create HashMap
    static Map<String, Object> objMap = new HashMap(); //Map of shipments
    public static void main(String[] args) {
        //Insert objects in HashMap
        objMap.put("integer", integ);
        objMap.put("string", strng);
        //Check the values
        System.out.println(objMap.get("integer"));
        System.out.println(objMap.get("string"));
        //Change values of underlying object
        integ=2;
        strng="Bye";
        //Check values again
        System.out.println(objMap.get("integer"));
        System.out.println(objMap.get("string"));
    }
}

还有输出:

debug:
1
Hi
BUILD SUCCESSFUL (total time: 8 seconds)

【问题讨论】:

标签: java dictionary hashmap


【解决方案1】:

您正在制造一些混乱。看这段代码:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

import org.junit.Before;
import org.junit.Test;

// Comment 0)
public class Test1 {
    Map<String, Object> objMap = new HashMap<>();

    private Integer integ = 1;
    private String strng = "Hi";

    // Comment 1)
    // private final Integer integ = 1;
    // private final String strng = "Hi";

    // Comment 2)
    final AtomicInteger integMutable = new AtomicInteger(1);
    final AtomicReference<String> strngMutable = new AtomicReference<>("Hi");

    @Before
    public void setup() {
        objMap.put("integer", integ);
        objMap.put("string", strng);
        objMap.put("integer2", integMutable);
        objMap.put("string2", strngMutable);
    }

    @Test
    public void test32886291() {
        // Comment 1: error raised if fields were final
        integ = 2;
        strng = "Bye";
        assertNotEquals(2, objMap.get("integer"));
        assertNotEquals("Bye", objMap.get("string"));

        integMutable.set(2);
        strngMutable.set("Bye");
        assertEquals(2, ((AtomicInteger) objMap.get("integer2")).intValue());
        assertEquals("Bye", objMap.get("string2").toString());
    }
}

评论 0) 首先,我使用 JUnit 将您的“测试”类变成了真正的测试类。

评论 1) 您似乎对“字段”、“引用”、“值”和“自动装箱”概念感到困惑。在地图中,您通过引用存储一个对象(这是您想要的)。 这就是为什么我首先将您的int(原始类型)替换为Integer(一个对象)。

当您执行integ = 2 时,您并未更改该对象的值:您正在重新分配名为“integ”的字段。添加“final”关键字会引发错误(“无法分配最终字段 Test1.integ”)并突出显示该点。 因此,更改字段值(为其分配另一个对象)对存储在地图中的对象没有影响。两个 assertNotEquals 语句证实了这一点。

评论 2) 无法更改“不可变”的 Integer 和 String 的值。我用“可变”对象替换了它们,分别包装了一个 int 值和一个字符串。预期的行为由两个 assertEquals 语句确认。

【讨论】:

    【解决方案2】:

    当你这样做时:

        integ=2;
        strng="Bye";
    

    您只更改了对对象的引用,而不是对象本身。

    对于IntegerString,您不能更改对象,因为它们是immutable

    因此,如果您想更改地图中的值,那么解决方案是:

    1. 从地图中删除以前的值。
    2. 更改值
    3. 将它们添加到您的地图中

    【讨论】:

      【解决方案3】:

      您需要再次输入值,以便在再次从地图中获取之前覆盖现有值。

      public static void main(String[] args) {
              //Insert objects in HashMap
              objMap.put("integer", integ);
              objMap.put("string", strng);
              //Check the values
              System.out.println(objMap.get("integer"));
              System.out.println(objMap.get("string"));
              //Change values of underlying object
              integ=2;
              strng="Bye";
              objMap.put("integer", integ);
              objMap.put("string", strng);
              //Check values again
              System.out.println(objMap.get("integer"));
              System.out.println(objMap.get("string"));
          }
      

      【讨论】:

        【解决方案4】:

        我认为您需要检查您的 Java 基础知识,因为参数恰好在 Java 中“按值传递”。

        这意味着objMap.put("integer", integ); 将在映射中存储integ 的值在“整数”键下。

        在此操作之后更改 integ 的值不会影响映射中存储的内容,因为映射包含对象在 .put() 操作时间的精确副本。

        这种方法与“按引用传递”相反,其中映射将包含“指向”变量integ 的“指针”。

        【讨论】:

          【解决方案5】:

          您已修改值,但尚未将它们放回 HashMap。

              integ=2;
              strng="Bye";
              objMap.put("integer", integ);
              objMap.put("string", strng);
          

          我认为,您假设哈希映射将引用修改后的值。但它不是那样工作的,在这种情况下,因为你正在存储原语。如果您将灵长类动物包裹在一个物体中,您的假设就会成立。

            public class MyClass{
               int integ;
            }
          

          【讨论】:

            【解决方案6】:

            Java 在此示例中使用按值调用,因此它仅在 HashMap 中存储实际值而不是引用。所以如果你改变了值,你应该把它重新放在 HashMap 中。

            希望对你有帮助。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-07-25
              • 1970-01-01
              • 2012-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-04-27
              • 2016-08-05
              相关资源
              最近更新 更多