[JAVA]如何定义好一个静态final域

来源:互联网 发布:清华大学c语言教材 编辑:程序博客网 时间:2024/06/14 20:00

背景描述:
最近在做一些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如果是浅拷贝则依旧会产生问题,这个时候外界一样可以对其进行修改。

综上,我更推荐使用第一种方式!

1 0
原创粉丝点击