不可变对象

admin
2022-04-22 / 0 评论 / 94 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2022年04月24日,已超过726天没有更新,若内容或图片失效,请留言反馈。

线程安全策略

不可变对象

不可变对象需要满足的条件:
对象创建以后其状态就不能修改
对象所有域都是final类型
对象是正确创建的(在对象创建期间,this引用没有逸出)


一、final关键字

final关键字:可修饰类、方法、变量。

修饰类:不能被继承

修饰方法

  1. 锁定方法不被继承类修改;
  2. 效率

修饰变量:基本数据类型变量、引用类型变量

代码示例

package com.yanxizhu.demo.concurrency.finals;

import com.google.common.collect.Maps;
import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

/**
 * @description: 不可变对象 final修饰
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/22 20:35
 * @version: 1.0
 */
@Slf4j
@UnThreadSafety
public class DemoFinal {
    //普通类型,final修饰后,修改直接提示错误
    private final static Integer a =1;
    //普通类型,final修饰后,修改直接提示错误
    private final static String b = "hello";
    //final修饰后不能在执行新的对象
    private final static Map<Integer, Integer> map = Maps.newHashMap();

    static {
        map.put(1, 2);
        map.put(2, 3);
        map.put(4, 5);
    }

    public static void main(String[] args) {
        //指向新的对象,直接报错
//        map = new Maps.newHashMap();

        //值可以修改,但是线程不安全
        map.put(1, 6);
        log.info("{}", map.get(1));
        // 输出结果:- 6
    }

    //fina修饰形参,传入后也不能修改
    public void test(final int a) {
        //报错
//        a =2;
    }

}

输出结果:

 - 6

二、Collections.unmodifiableXXXXX

代码示例

package com.yanxizhu.demo.concurrency.finals;

import com.google.common.collect.Maps;
import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety;
import lombok.extern.slf4j.Slf4j;

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

/**
 * @description: Collections.unmodifiableXXXXX,值是不能修改的,但是是线程安全的
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/22 21:12
 * @version: 1.0
 */
@Slf4j
@UnThreadSafety
public class DemoCollections {

    private static Map<Integer, Integer> map = Maps.newHashMap();

    static {
        map.put(1, 2);
        map.put(3, 4);
        map.put(5, 6);
        map = Collections.unmodifiableMap(map);
    }

    public static void main(String[] args) {
        map.put(1, 8);
        log.info("{}", map.get(1));
    }

}

输出结果:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.base/java.util.Collections$UnmodifiableMap.put(Collections.java:1457)
    at com.yanxizhu.demo.concurrency.finals.DemoCollections.main(DemoCollections.java:28)

Collections.unmodifiableXXXXX创建的不能修改,修改提示"UnsupportedOperationException"。但是是线程安全的。

常见方法有

三、google的Guava工具类,ImmutableXXX

代码示例

package com.yanxizhu.demo.concurrency.finals;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.yanxizhu.demo.concurrency.annotation.ThreadSafety;

/**
 * @description: google Guava工具类实现对象不可变,线程安全,但是不能修改值
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/22 21:39
 * @version: 1.0
 */
@ThreadSafety
public class DemoGuavaImmutableXXX {
    //ImmutableList会提示不能修改,建议用这个
    private final static ImmutableList list = ImmutableList.of(2,3,5);

    //list不会提示不能修改
//    private final static List<Integer> list = ImmutableList.of(2,3,5);

    //set同理不能修改值
    private final static ImmutableSet set = ImmutableSet.copyOf(list);

    //map方式一,map用法有点区别,是key,value的形式                                           //(key1,value1,key2,value2,.......)
    private final static ImmutableMap<Integer, Integer> map = ImmutableMap.of(1,2,3,4,5,6);
    //map方法二,初始值有点不同
    private final static ImmutableMap<Integer, Integer> map2 = ImmutableMap.<Integer, Integer>builder().
            put(1, 2).put(3, 4).put(5, 6).build();

    public static void main(String[] args) {
        //提示错误:UnsupportedOperationException
//        list.add(4);

        //set同样会提示不能修改,提示".UnsupportedOperationException"
//        set.add(4);

        //map同理,不能修改值,否则也提示 UnsupportedOperationException
        map.put(3, 2);
    }
}

输出结果:

Exception in thread "main" java.lang.UnsupportedOperationException
    at com.google.common.collect.ImmutableMap.put(ImmutableMap.java:780)
    at com.yanxizhu.demo.concurrency.finals.DemoGuavaImmutableXXX.main(DemoGuavaImmutableXXX.java:40)

注意:是不能修改,读取是没问题的。

使用不可变对象时,注意实际业务看法种,对象是否不可以变,不可变才使用上面3种方法,实现不可变对象。

3

评论 (0)

取消