文章目录
不可变对象
一、介绍
不可变对象,顾名思义。不可变对象是避免对象被发布的一个重要的手段。
对象不可变需要满足以下条件
- 对象创建以后其状态就不能修改
- 对象所有域都是 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) {
//上面的都不可修改
}
}
关键在于通过工具类会使用即可