背景描述:
最近在做一些JAVA方面的开发,时常需要定义一些常量,比如String类,Map类等等。
public static final String ADDRESS = "CSDN";
上述的定义很常见,但是对于如何定义一个常量的map,看了公司一些同事的做法如下:
public class Constants{
public static final Map<String,String> ADDRESS_MAP=new HashMap<>();
static{
ADDRESS_MAP.put("1","CSDN");
ADDRESS_MAP.put("2","CNBLOGS");
}
}
其实这种做法是及其不安全的,读者有兴趣的可以尝试下,在外部调用:
public static void main(String[] args) {
Constants.ADDRESS_MAP.put("1","333");
System.out.println(Constants.ADDRESS_MAP);
}
很不幸,我们的值被改变了。
今天抽了半个小时的时间,学习了下,特总结之。
首先先介绍2个概念,不可变对象和可变对象。从别人博客上找来了一个这个的定义。引用自CSDN博客,可点击访问。
可变类和不可变类(Mutable and Immutable Objects)的初步定义:
可变类:当你获得这个类的一个实例引用时,你可以改变这个实例的内容。
不可变类:当你获得这个类的一个实例引用时,你不可以改变这个实例的内容。不可变类的实例一但创建,其内在成员变量的值就不能被修改。
Map、List都是可变对象,因此我们将其定义成final域并没有实际的效果。
下面提供2种做法:(参考自effective java第13条)
Method 1:
public static final Map<String,String> MAP = Collections.unmodifiableMap(new HashMap<String,String>()
{
private static final long serialVersionUID = 1338447211708407707L;
{
put("1","2");
}
}
);
这个时候再想改变其值,就是不可能的了,当然这个时候的final修饰符也没什么意义了。
Method 2:
使用clone方法。将可变对象定义成private类型的,并且提供一个静态方法去获得这个对象的clone返回值。
当Map的value是不可变对象的时候,这个方法的确是可以的,但是当value是一个可变对象的时候,我们发现,这种方法并不有效。如下例子(这里的对象就不给出啦,很简单的一个对象)。
private static final HashMap<String,Book> ADDRESS_MAP=new HashMap<>();
static{
ADDRESS_MAP.put("1",new Book("sss","qqq"));
ADDRESS_MAP.put("2",new Book("qqqxx","mmmxx"));
}
public static Map<String,Book> get_address_map(){
return (Map<String, Book>) ADDRESS_MAP.clone();
}
note:但是本人不建议使用方法2,因为clone如果是浅拷贝则依旧会产生问题,这个时候外界一样可以对其进行修改。
综上,我更推荐使用第一种方式!