【Java并发编程】不可变对象

不可变对象

一、介绍

不可变对象,顾名思义。不可变对象是避免对象被发布的一个重要的手段。

对象不可变需要满足以下条件

  • 对象创建以后其状态就不能修改
  • 对象所有域都是 final类型
  • 对象是正确创建的(在对象创建期间,this引用没有逸出)

对象只有一种状态,并且该状态一般由构造函数来控制。

final关键字是Java SE的基础部分,这里不再多说,它可用于修饰类、方法、变量

  • 修饰类:不能被继承
  • 修饰方法:1、锁定方法不被继承类修改;2、效率
  • 修饰变量:基本数据类型变量、引用类型变量

即使可以作为形参的修饰(如下面的例子) 如果是基本数据类型 也是不可以修改的

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

对象的正确创建可以参考 【Java并发编程】安全发布对象

你可能觉得不可变对象不是很简单吗? 其实还有一个常见的问题会困扰我们,下面我们看一个例子:

import java.util.HashMap;
import java.util.Map;

public class Test {

    private static final Map<Integer,Integer> MAP = new HashMap<Integer, Integer>();

    public static void main(String[] args) {
        MAP.put(1,1);
        MAP.put(3,3);
        MAP.put(5,5);
        System.out.println(MAP);
    }
}

结果:
在这里插入图片描述
MAP虽然声明为final但状态仍然是可变的,其他集合亦是如此。

我们下面着手解决集合框架的状态问题。

二、集合框架的不可变

解决这类问题有两种比较常用的手段

(1)Collections.unmodifiableXXX : Collection、List、Set、Map....
(2)Guava:ImmutableXXX:Collection、List、Set、Map.......

Collections.unmodifiableXXX是Java内置的,Guava则是第三方依赖

Collections.unmodifiableXXX的使用是相当简单的,如下:

package com.tomcat.server;

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

public class Test {

    private static Map<Integer,Integer> MAP = new HashMap<>();

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

    public static void main(String[] args) {
        System.out.println(MAP);
    }
}

结果:
在这里插入图片描述


Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。 所有这些工具每天都在被Google的工程师应用在产品服务中。

我们这里更多的关注的是不可变集合: 用不变的集合进行防御性编程和性能提升。

maven依赖

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>28.0-jre</version>
        </dependency>

以unmodifiableMap为例,核心方法的源码如下:

    public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
        return new UnmodifiableMap<>(m);
    }

演示一下:

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import lombok.extern.slf4j.Slf4j;

import java.util.List;


@Slf4j
public class ImmutableExample {

    private final static ImmutableList LIST =ImmutableList.of(1,2,3);
//    直接使用list也是OK的
//    private final static List<Integer> LIST =ImmutableList.of(1,2,3);

    private final static ImmutableSet SET = ImmutableSet.copyOf(LIST);

    // ImmutableMap.of()要求值是成对出现的 一个为key 一个为value
    private final static ImmutableMap<Integer,Integer> MAP = ImmutableMap.of(1,2,3,4,5,6,7,8);

    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) {
        //上面的都不可修改
        
    }
}

关键在于通过工具类会使用即可

发布了127 篇原创文章 · 获赞 3078 · 访问量 36万+

猜你喜欢

转载自blog.csdn.net/qq_42322103/article/details/102798472