不可变对象

阿里云服务器 新用户 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));

    }
}

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

猜你喜欢

转载自blog.csdn.net/andy86869/article/details/79832222