【问题标题】:How can we make a HashMap-typed parameter not editable?我们如何使 HashMap 类型的参数不可编辑?
【发布时间】:2013-03-21 14:45:20
【问题描述】:

抱歉,我的标题可能具有误导性。

这其实是我最近的一次JAVA面试,面试官问我这个问题:如果我们有一个HashMap类型的参数,我们怎么能保证在accepting方法中,用户没有办法修改这个HashMap(即get()方法)

我在面试的时候说用final,面试官根本不领情,在网上找了半天这个话题还是没有头绪。

专家可以帮忙吗?谢谢

【问题讨论】:

    标签: java


    【解决方案1】:

    听起来您可能来自 C++ 背景,其中设置参数const 确实会阻止该方法修改对象。在 Java 中,final 仅阻止分配给该变量;您仍然可以调用修改对象本身的方法。

    所以,例如:

    void callingMethod() {
       HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
       map.put(1, 2);
    
       badMethod(map);
    
       // NullPointerException
       System.out.println(map.get(1).intValue());
    }
    
    void badMethod(final HashMap<Integer, Integer> map) {
       map.clear();
    }
    

    有几种方法可以防止这种情况:

    1. 在调用方法之前创建一个defensive copy
    2. 使用Collections将对象包装在不可修改的包装器中
    3. 使用明确的不可变类型,例如Guava 提供的类型

    【讨论】:

      【解决方案2】:

      使用final 不会阻止调用引用上的方法。它只会使引用本身不可更改。所以你的答案是错误的。

      我的建议是使用泛型(仅用于此类采访,而不是在程序中!):

          Map<String, String> map = new HashMap< String, String >();
          map.put("a", "b"); // OK
      
          Map< ? extends String, ? extends String > mapRO = new HashMap< String, String >();
          mapRO.put("a", "b"); // Compile error
          String value = mapRO.get("a"); // OK
      

      如您所见,使用? extends ... 隐藏泛型类型可防止调用“写入”方法(如put),因为它们通常需要完全定义类型。但是你仍然可以拨打clear(),所以这是一个非常池安全的概念。

      您也可以使用一些包装器,它会在所有“写入”方法调用时引发异常。

      【讨论】:

      • 这个非直接回答的目的是用这个问题来展示你对泛型的了解。
      • 即使我坚持相同,但你确实意识到没有什么可以扩展 String 吗?
      • @PermGenError 是的,但它有效! Java 编译器没那么聪明:-)
      • 实际上 javac 比我们想象的要聪明得多。它发出警告,说 dude/dudette 您正在寻找扩展 String 的东西。由于字符串是最终的,没有其他类可以扩展它:P .. :)
      • @PermGenError 使用 oracle javac 1.7.0_09 或 eclipse 3.8 JDT 编译器编译它时,我没有收到任何警告。顺便说一句,在问题中没有提到String 类型。因此,您可以采用任何其他类型,可以作为示例进行子类化。
      【解决方案3】:

      我认为这是不可变或不可修改的地图。

      Collections#unmodifiableCollection

      它返回指定地图的不可修改视图。这种方法 允许模块为用户提供对内部的“只读”访问 地图。对返回映射的查询操作“通读”到 指定地图,并尝试修改返回的地图,是否直接 或通过其集合视图,导致 UnsupportedOperationException。

      Reference

      【讨论】:

        【解决方案4】:

        使用Collections.unmodifiableMap包裹您正在传递的地图

        【讨论】:

          【解决方案5】:

          Collections.unmodifiableMap(myMap) 将返回只读映射。您应该处理由此返回的 Map 对象。

          【讨论】:

            【解决方案6】:

            如何从该 Hashmap 中创建一个不可修改的 Collection,例如 here?

            然后你会这样做: yourMethod(Collections.unmodifiableMap(yourHashmap)); 仅使用 final 意味着您将无法在此块中用另一个引用覆盖该引用,它不会阻止对该对象的任何方法调用

            【讨论】:

              【解决方案7】:

              有两种方法

              1) this.map = Collections.unmodifiableMap(map);

              2) 防御性复制:this.map = new HashMap(map);

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-08
                • 1970-01-01
                • 2020-10-31
                • 1970-01-01
                • 2019-06-17
                • 1970-01-01
                相关资源
                最近更新 更多