Java并发基础(二):如何实现一个不可变类?

x33g5p2x  于2021-09-19 转载在 Java  
字(3.0k)|赞(0)|评价(0)|浏览(449)

1、如何将一个类改造成不可变类?

将一个类改造成不可变类,来解决线程安全问题。

实现不可变类的一些思路:

使用final关键字修饰所有成员变量,避免其被修改,也可以保证多线程环境下被final关键字修饰的变量所引用的对象的初始化安全,即final修饰的字段在其他线程可见时,必定是初始化完成的。
1.
使用private修饰所有成员变量,可以防止子类及其他地方通过引用直接修改变量值。
1.
禁止提供修改内部状态的公开接口(比如我们前面例子中的setXY方法)
1.
使用final修饰类,禁止不可变类被外部继承,防止子类改变其定义的方法的行为。
1.
如果类中存在数组或集合,在提供给外部访问之前需要做防御性复制

防御性复制理解

public final class DefensiveDemo {
    private final List<Integer> list = new ArrayList<Integer>();
    
    public DefensiveDemo(){
        list.add(1);
        list.add(2);
        list.add(3);
    }
    
    public List<Integer> getData(){
        return list;
    }

    public static void main(String[] args) {
        DefensiveDemo defensiveDemo = new DefensiveDemo();
        List<Integer> data = defensiveDemo.getData();
        data.add(4);
    }

}

代码中能够对集合修改,不能保证不可变对象。

public List<Integer> getData(){
//        return list;
        return Collections.unmodifiableList(new ArrayList<Integer>(list));
    }

Exception in thread "main" java.lang.UnsupportedOperationException

使用Collections.unmodifiableList方法进行包装,这样能保证外部无法修改(添加元素)我们返回的结果,那么DefensiveReplicaDemo的data集合的值永远会是1,2,3。

防御性的深度拷贝

public class DeepCopyObjectTest {

    public static void main(String[] args) {
        Map<Integer,Student> map = Maps.newHashMap();
        map.put(1,new Student("xiaoli",18));

//        copy(map);
//        deepCopy(map);

        baseCopy();
    }

    public static void copy(Map<Integer,Student> map){
        System.out.println(map.get(1).getName());
        Map<Integer,Student> newMap =  Collections.unmodifiableMap(map);
        newMap.get(1).setName("xiaowang");
        System.out.println(map.get(1).getName());
    }

    public static void deepCopy(Map<Integer,Student> map){
        Map<Integer,Student> newMap = new HashMap<>(map.size());
        for (Map.Entry<Integer,Student> entry:map.entrySet()) {
            newMap.put(entry.getKey(),new Student(entry.getValue()));
        }
        newMap.put(2,new Student("xiaosun",20));

        Map<Integer,Student> result = Collections.unmodifiableMap(newMap);
        result.get(1).setName("xiaozhao");
        System.out.println(result.get(1).getName());

        System.out.println(map.get(1).getName());
        //Exception in thread "main" java.lang.UnsupportedOperationException
        //result.put(2,new Student("xiaosun",20));
    }

    public static void baseCopy(){
        Map<Integer,String> isMap = Maps.newHashMap();
        isMap.put(1,"a");
        isMap.put(2,"b");
        Map<Integer,String> isMapCopy =  Collections.unmodifiableMap(isMap);
       // Exception in thread "main" java.lang.UnsupportedOperationException
//        isMapCopy.put(1,"aa");
        //Exception in thread "main" java.lang.UnsupportedOperationException
//        isMapCopy.put(3,"c");
        isMap.put(1,"aa");
        isMap.put(3,"c");
        System.out.println(isMap);//{1=aa, 2=b, 3=c}
        System.out.println(isMapCopy);//{1=aa, 2=b, 3=c}
        //== 是比较内存地址是否相同,equals 是比较内存地址上面的值是否相同
        System.out.println(isMap == isMapCopy);
        System.out.println(isMap.equals(isMapCopy));
    }
}

unmodifiableMap理解

        返回指定有序映射的不可修改视图。此方法允许模块为用户提供对内部有序映射的“只读”访问。在返回的有序映射上执行的查询操作将“读完”指定的有序映射。试图修改返回的有序映射(无论是直接修改、通过其 collection 视图修改,还是通过其 subMap、 headMap或 tailMap视图修改)将导致抛出 UnsupportedOperationException。
就是说unmodifiableMap不能添加新的元素,并不能对基本类型进行修改。

Map<Integer,StringBuilder> unmodifiableMap=Collections.unmodifiableMap(map);

相关文章

最新文章

更多