# 6.1不可变对象

有一种对象，只要发布了就是安全的，那就是不可变对象

## 不可变对象需要满足的条件

* 对象创建以后其状态就不能修改
* 对象所有域都是final类型
* 对象是正确创建的（再对象创建期间，this应用没有溢出）

## 如何实现以上条件

* 将类申明为final，这样类就不可别继承
* 将成员声明为私有的，这样就不能够直接访问这些成员
* 对变量不提供set方法
* 将所有可变的成员声明为final，这样成员就只能被赋值一次
* 通过构造器初始化所有成员，进行深度拷贝
* 在get方法中，不直接返回对象的本身，而是克隆对象并返回对象的拷贝

> 对于创建一个不可变对象，大家多参考一下String类

## 定义不可变对象的手段

* final关键字：类、方法、变量
* Collections.unmodifiableXXX： Collection、List、Set、Map...
* Guava：ImmutableXXX： Collection、List、Set、Map...

## final关键字：类、方法、变量

* 修饰类：不能被继承

  final类中的成员变量可以根据需要使用final修饰，但需要注意final类中的所有成员方法都会被隐式的声明为final方法，使用final修饰类要谨慎，除非这个类以后真的不会用来继承或出于安全的考虑，不然尽量不要使用final类
* 修饰方法：锁定方法不被继承类修改

  注意：一个类的private方法会被隐式的声明为final方法
* 修饰变量：基本数据类型变量、引用类型变量

  对于基本数据类型变量，一旦使用final修饰，则其数值一旦被赋值之后，就不可被修改了

  对于引用类型变量，一旦使用final修饰，则变量初始化后，就不可再指向其他变量

```java
package com.moluo.concurrency.immutable;

import com.google.common.collect.Maps;
import java.util.HashMap;
import java.util.Map;

public class FinalExample {
    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) {
        // A = 2; // 使用final修饰基本数据类型变量，不可再被修改，该写法报错
        // B = "hello"; // 使用final修饰基本数据类型变量，不可再被修改，该写法报错
        // map = new HashMap<>(1); // 使用final修饰引用类型变量，不可再指向其他变量，该写法报错
        map.put(1, 3); // 使用final修饰引用类型变量，不可再指向其他变量，但却约束不了对初始变量值的改变
        System.out.println(map.get(1));
    }

    private void test(final int a) {
        // a=1; // 使用final关注字修饰入参，入参一旦传入将不允许被修改
    }
}
```

## Collections.unmodifiableXXX： Collection、List、Set、Map...

```java
package com.moluo.concurrency.immutable;

import com.google.common.collect.Maps;
import java.util.Collections;
import java.util.Map;

public class CollectionsExample {

    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); // 使用Collections.unmodifiableMap包装引用类型变量后，当尝试修改引用变量的数值时，将抛出UnsupportedOperationException
        System.out.println(map.get(1));
    }
}
```

## Guava：ImmutableXXX： Collection、List、Set、Map...

```java
package com.moluo.concurrency.immutable;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

public class ImmutableExample {
    private static ImmutableList list = ImmutableList.of(1, 2, 3);
    private static ImmutableMap map = ImmutableMap.builder()
            .put(1, 2).put(3, 4).put(5, 6).build();

    public static void main(String[] args) {
        // list.add(4); // 使用ImmutableList，当尝试向list中添加新元素时，将抛出UnsupportedOperationException
        map.put(1, 3); // 使用ImmutableMap，当尝试更改map元素时，将抛出UnsupportedOperationException
        System.out.println(map.get(1));
    }
}
```
