欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

不可变对象

程序员文章站 2022-05-08 19:41:43
...

阿里云服务器 新用户 99 元/ 年 , 1 核 2 G 1 M带宽 40 G SSD硬盘 , 最低¥7.8/月, 需要的小伙伴赶紧上车吧 点击链接
不可变对象
有一种对象它只要发布了就是安全的 ,它就是不可变对象 . 比如我们最常用的 String 类型
不可变对象需要满足的条件

  1. 对象创建之后其状态不可改变
  2. 对象的所有域都是final类型
  3. 对象是正确创建的 (指的是对象创建期间, this 引用没有逸出)

final 关键字 : 可以用来修饰类 ,方法 ,变量

  • 修饰类 被修饰的类不能被继承
  • 修饰方法 1. 锁定方法不被继承类修改 2 .效率
  • 修饰变量 基本类型的变量(一旦初始化就不能被修改) 引用类型的变量( 初始化之后不能让它指向另外的变量)

代码示例1


import com.google.common.collect.Maps;
import com.mmall.concurrency.annoations.NotThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

/**
 * Created by Charles Date:2018/3/21
 * <p>
 * final 修饰基础类型数据, 不可被修改 , 若修饰类,被修饰的类不能被继承
 * 如果修饰引用类型的变量的话,不能再指向另外的一个对象
 */
@Slf4j
public class ImmutableExample1 {

    private final static Integer a = 1;

    private final static String b = "2";

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

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

    public static void main(String[] args) {
        // 下面三行代码编译的时候就会出错 , 如果在IEDA 等编辑器中 直接提示下滑红线
        a = 2 ;     // 修饰基础类型数据, 不可被修改
        b ="3";     // 修饰基础类型数据, 不可被修改
        map = Maps.newHashMap();    // 修饰引用类型的变量的话,不能再指向另外的一个对象
            map.put(1, 3); // 可以修改引用变量的值
        log.info("{}", map.get(1));

    }

    private void test(final int a) {
//        a = 1;
    }
}

不可变对象

Java 里面除了 final 可以定义不可变对象之外, 还有其他的方法来定义.
Java里面提供一个类 Collections 在这个类中提供了许多以 unmodifiable为前缀的方法 , 如 list map set 等 如下图 , 这些都是不可以被修改的方法 , 只要将我们定义的对象传到对应的方法里面, 就不能别修改了 .
不可变对象

代码示例 2


import com.google.common.collect.Maps;
import com.mmall.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

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

/**
 *
 *  Collections.unmodifiableMap 处理过的map 是不能后被修改的
 */
@Slf4j
@ThreadSafe
public class ImmutableExample2 {

    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, 3);
        log.info("{}", map.get(1));

    }
}

上面这段演示代码就会抛出异常 , 如下图
不可变对象
还有 Google的 一个开源库 Guava 它里面也有提供以 Immutable 为前缀的类 ,后面跟着 list ,set map 等 , 这些类都提供了带初始化数据的申明方法. 因此我们在申明一个 Immutable相关类的方法实例的时候 ,只需要调用它带上初始化方法就可以, 一旦初始化完成 , 就不能被修改了 .

代码演示 3

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.mmall.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

/**
 *
 *  Collections.unmodifiableMap 处理过的map 是不能后被修改的
 */
@Slf4j
@ThreadSafe
public class ImmutableExample3 {

    private final static ImmutableList list = ImmutableList.of(1, 2, 3, 4);

    private final static ImmutableSet set = ImmutableSet.copyOf(list);

    private final static ImmutableMap<Integer,Integer> map = ImmutableMap.of(1,2);

    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) {
//        set.add(4);
//        map.put(1,4);
//        map2.put(3, 5);
        log.info("{}",map2.get(3));

    }
}

小结
对于不可变对象 , 只要能通过一些类 ,工具类能够会使用就可以 . 在实际开发中, 我们要实际分析程序变量是否可以做成不可变对象, 如果可以的话, 尽量让它变成不可比的对象 , 这样在多线程情况下就不会出现线程安全的问题.