不可变对象
阿里云服务器 新用户 99 元/ 年 , 1 核 2 G 1 M带宽 40 G SSD硬盘 , 最低¥7.8/月, 需要的小伙伴赶紧上车吧 点击链接
不可变对象
有一种对象它只要发布了就是安全的 ,它就是不可变对象 . 比如我们最常用的 String
类型
不可变对象需要满足的条件
- 对象创建之后其状态不可改变
- 对象的所有域都是
final
类型 - 对象是正确创建的 (指的是对象创建期间,
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));
}
}
小结
对于不可变对象 , 只要能通过一些类 ,工具类能够会使用就可以 . 在实际开发中, 我们要实际分析程序变量是否可以做成不可变对象, 如果可以的话, 尽量让它变成不可比的对象 , 这样在多线程情况下就不会出现线程安全的问题.
上一篇: Mysql主从复制 读写分离 分库分表 Mycat高可用
下一篇: jquery js实现动画时钟