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修饰,则变量初始化后,就不可再指向其他变量

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...

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...

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));
    }
}

Last updated

Was this helpful?