关于Collections.unmodifiableMap的一些理解

本文深入探讨了Java中Collections.unmodifiableMap方法的实现原理及使用场景。解释了它如何提供只读视图,并讨论了其限制,即不能阻止内部对象状态的改变。

最近在研究common-lang下的ClassUtils源代码到时候,下面代码里面使用到了

static {
        final Map<String, String> m = new HashMap<String, String>();
        m.put("int", "I");
        m.put("boolean", "Z");
        m.put("float", "F");
        m.put("long", "J");
        m.put("short", "S");
        m.put("byte", "B");
        m.put("double", "D");
        m.put("char", "C");
        m.put("void", "V");
        final Map<String, String> r = new HashMap<String, String>();
        for (final Map.Entry<String, String> e : m.entrySet()) {
            r.put(e.getValue(), e.getKey());
        }
        <span style="color:#ff0000;">abbreviationMap = Collections.unmodifiableMap(m);
        reverseAbbreviationMap = Collections.unmodifiableMap(r);</span>
    }
后面查看帮助文档的时候和Collections.unmodifiableMap的代码的时候, Collections.unmodifiableMap返回的是一个不可修改的Map,

通过阅读帖子和实验,其实这个不可修改的Map指的是Map中的对象地址不可修改,里面的对象若支持修改的话,其实也还是可以修改的。

请看两位大神的解释

1.Cameron Skinner

Collections.unmodifiableMap guarantees that the map will not be modified. It's mostly useful if you want to return a read-only view of an internal map from a method call, e.g:

class A {
    private Map importantData;

    public Map getImportantData() {
        return Collections.unmodifiableMap(importantData);
    }
}

This gives you a fast method that does not risk the client changing your data. It's much faster and more memory efficient than returning a copy of the map. If the client really does want to modify the returned value then they can copy it themselves, but changes to the copy won't be reflected in A's data.

If you are not returning map references to anyone else then don't bother making it unmodifiable unless you are paranoid about making it immutable. You can probably trust yourself to not change it.

2.Don

Cameron Skinner's statement above that "Collections.unmodifiableMap guarantees that the map will not be modified" is actually only partly true in general, although it happens to be accurate for the specific example in the question (only because the Character object is immutable). I'll explain with an example.

Collections.unmodifiableMap actually only gives you protection that the references to objects held in the map cannot be changed. It does that by restricting the 'put' into the map that it returns. However, the original encapsulated map can still be modified from outside the class because Collections.unmodifiableMap does not make any copies of the contents of the map.

In the question posted by Paulo, the Character objects held in the map are luckily unmodifiable. However, in general this may not be true and the unmodifiability advertised by Collections.unmodifiableMap should not be the only safeguard. For instance, see the example below.

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class SeeminglyUnmodifiable {
   private Map<String, Point> startingLocations = new HashMap<String, Point>(3);

   public SeeminglyUnmodifiable(){
      startingLocations.put("LeftRook", new Point(1, 1));
      startingLocations.put("LeftKnight", new Point(1, 2));
      startingLocations.put("LeftCamel", new Point(1, 3));
      //..more locations..
   }

   public Map<String, Point> getStartingLocations(){
      return Collections.unmodifiableMap(startingLocations);
   }

   public static void main(String [] args){
     SeeminglyUnmodifiable  pieceLocations = new SeeminglyUnmodifiable();
     Map<String, Point> locations = pieceLocations.getStartingLocations();

     Point camelLoc = locations.get("LeftCamel");
     System.out.println("The LeftCamel's start is at [ " + camelLoc.getX() +  ", " + camelLoc.getY() + " ]");

     //Try 1. update elicits Exception
     try{
        locations.put("LeftCamel", new Point(0,0));  
     } catch (java.lang.UnsupportedOperationException e){
        System.out.println("Try 1 - Could not update the map!");
     }

     //Try 2. Now let's try changing the contents of the object from the unmodifiable map!
     camelLoc.setLocation(0,0);

     //Now see whether we were able to update the actual map
     Point newCamelLoc = pieceLocations.getStartingLocations().get("LeftCamel");
     System.out.println("Try 2 - Map updated! The LeftCamel's start is now at [ " + newCamelLoc.getX() +  ", " + newCamelLoc.getY() + " ]");       }
}

class Point{
	public float x;
	public float y;
	public Point(float x, float y){
		setLocation(x, y);
	}
	public void setLocation(float x, float y){
		this.x = x;
		this.y = y;
	}
	
	public float getX(){
		return x;
	}
	
	public float getY(){
		return y;
	}
}
哈哈,我只是stackoverflow的搬运工!参考帖子:http://stackoverflow.com/questions/3999086/when-is-the-unmodifiablemap-really-necessary


D:\Program Files\elasticsearch-8.9.0\bin>elasticsearch-setup-passwords.bat interactive 09:23:57.180 [main] WARN org.elasticsearch.deprecation.common.settings.Settings - data_stream.dataset="deprecation.elasticsearch" data_stream.namespace="default" data_stream.type="logs" elasticsearch.event.category="settings" event.code="keystore.password" message="[keystore.password] setting was deprecated in Elasticsearch and will be removed in a future release." Exception in thread "main" org.elasticsearch.ElasticsearchSecurityException: failed to load SSL configuration [xpack.security.transport.ssl] - cannot specify both [keystore.secure_password] and [keystore.password] at org.elasticsearch.xpack.core.ssl.SSLService.lambda$getSSLConfigurations$4(SSLService.java:550) at java.base/java.util.HashMap.forEach(HashMap.java:1429) at java.base/java.util.Collections$UnmodifiableMap.forEach(Collections.java:1553) at org.elasticsearch.xpack.core.ssl.SSLService.getSSLConfigurations(SSLService.java:542) at org.elasticsearch.xpack.core.ssl.SSLService.<init>(SSLService.java:147) at org.elasticsearch.xpack.core.security.CommandLineHttpClient.execute(CommandLineHttpClient.java:149) at org.elasticsearch.xpack.core.security.CommandLineHttpClient.execute(CommandLineHttpClient.java:112) at org.elasticsearch.xpack.security.authc.esnative.tool.SetupPasswordTool$SetupCommand.checkElasticKeystorePasswordValid(SetupPasswordTool.java:340) at org.elasticsearch.xpack.security.authc.esnative.tool.SetupPasswordTool$InteractiveSetup.execute(SetupPasswordTool.java:203) at org.elasticsearch.common.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:54) at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:85) at org.elasticsearch.cli.MultiCommand.execute(MultiCommand.java:94) at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:85) at org.elasticsearch.cli.Command.main(Command.java:50) at org.elasticsearch.launcher.CliToolLauncher.main(CliToolLauncher.java:64) Caused by: org.elasticsearch.common.ssl.SslConfigException: cannot specify both [keystore.secure_password] and [keystore.password]
06-11
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值