java基础——如何实现不可变类

转自https://blog.csdn.net/ksjay_1943/article/details/53353359
String、Long、Double是不可变类

实现不可变类的步骤

1)类声明为final,不可以被继承
2)所有成员是私有的,不允许直接被访问
3)对变量不要setter方法
4)所有可变的变量是final的,只能赋值一次
5)通过构造器初始化所有成员,进行深拷贝
6)在getter方法中不能返回对象本身,返回对象的拷贝

package FinalClassDemo;

import java.util.HashMap;
import java.util.Iterator;

public final class FinalClassExample {

    private final int id;

    private final String name;

    private final HashMap testMap;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    /**
     * 可变对象的访问方法
     */
    public HashMap getTestMap() {
        //return testMap;
        return (HashMap) testMap.clone();
    }

//    /**
//     * 实现深拷贝(deep copy)的构造器
//     * @param i
//     * @param n
//     * @param hm
//     */
//
//    public FinalClassExample(int i, String n, HashMap hm){
//        System.out.println("Performing Deep Copy for Object initialization");
//        this.id=i;
//        this.name=n;
//        HashMap tempMap=new HashMap();
//        String key;
//        Iterator it = hm.keySet().iterator();
//        while(it.hasNext()){
//            key= (String) it.next();
//            tempMap.put(key, hm.get(key));
//        }
//        this.testMap=tempMap;
//    }

    /**
     * 实现浅拷贝(shallow copy)的构造器
     * @param i
     * @param n
     * @param hm
     */

     public FinalClassExample(int i, String n, HashMap hm){
     System.out.println("Performing Shallow Copy for Object initialization");
     this.id=i;
     this.name=n;
     this.testMap=hm;
     }


    /**
     * 测试浅拷贝的结果
     * 为了创建不可变类,要使用深拷贝
     * @param args
     */
    public static void main(String[] args) {
        HashMap h1 = new HashMap();
        h1.put("1", "first");
        h1.put("2", "second");

        String s = "original";

        int i=10;

        FinalClassExample ce = new FinalClassExample(i,s,h1);

        //Lets see whether its copy by field or reference
        System.out.println(s==ce.getName());
        System.out.println(h1 == ce.getTestMap());
        //print the ce values
        System.out.println("ce id:"+ce.getId());
        System.out.println("ce name:"+ce.getName());
        System.out.println("ce testMap:"+ce.getTestMap());
        //change the local variable values
        i=20;
        s="modified";
        h1.put("3", "third");
        //print the values again
        System.out.println("ce id after local variable change:"+ce.getId());
        System.out.println("ce name after local variable change:"+ce.getName());
        System.out.println("ce testMap after local variable change:"+ce.getTestMap());

        HashMap hmTest = ce.getTestMap();
        hmTest.put("4", "new");

        System.out.println("ce testMap after changing variable from accessor methods:"+ce.getTestMap());

    }

}
//浅拷贝测试结果:
Performing Shallow Copy for Object initialization
true
false
ce id:10
ce name:original
ce testMap:{1=first, 2=second}
ce id after local variable change:10
ce name after local variable change:original
ce testMap after local variable change:{1=first, 2=second, 3=third}
ce testMap after changing variable from accessor methods:{1=first, 2=second, 3=third}
//深拷贝测试结果:
Performing Deep Copy for Object initialization
true
false
ce id:10
ce name:original
ce testMap:{1=first, 2=second}
ce id after local variable change:10
ce name after local variable change:original
ce testMap after local variable change:{1=first, 2=second}
ce testMap after changing variable from accessor methods:{1=first, 2=second}

注意:

1)不可变类只有getter方法
2)不可变类只有一个私有的构造器,以Builder对象作为参数来创建不可变对象
3)如果成员是可变的(如HAshMap),需要使用深拷贝或克隆来防止成员变量被改变
4)使用建造者模式创建不可变类
使用建造者模式来创建不可变类:

package FinalClassDemo;

import java.util.HashMap;

public class ImmutableClass {

    //required fields
    private int id;
    private String name;

    //optional fields
    private HashMap properties;
    private String company;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public HashMap getProperties() {
        //return cloned object to avoid changing it by the client application
        return (HashMap) properties.clone();
    }

    public String getCompany() {
        return company;
    }

    private ImmutableClass(ImmutableClassBuilder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.properties = builder.properties;
        this.company = builder.company;
    }

    //Builder class
    public static class ImmutableClassBuilder{
        //required fields
        private int id;
        private String name;

        //optional fields
        private HashMap properties;
        private String company;

        public ImmutableClassBuilder(int i, String nm){
            this.id=i;
            this.name=nm;
        }

        public ImmutableClassBuilder setProperties(HashMap hm){
            this.properties = (HashMap) hm.clone();
            return this;
        }

        public ImmutableClassBuilder setCompany(String comp){
            this.company = comp;
            return this;
        }

        public ImmutableClass build(){
            return new ImmutableClass(this);
        }
    }
}

测试以上:

package FinalClassDemo;

import java.util.HashMap;

public class ImmutableBuilderTest {

    public static void main(String[] args) {

        // Getting immutable class only with required parameters
        ImmutableClass immutableClass = new ImmutableClass.ImmutableClassBuilder(1, "Pankaj").build();

        HashMap hm = new HashMap();
        hm.put("Name", "Pankaj");
        hm.put("City", "San Jose");
        // Getting immutable class with optional parameters
        ImmutableClass immutableClass1 = new ImmutableClass.ImmutableClassBuilder(1, "Pankaj")
                .setCompany("Apple").setProperties(hm).build();

        //Testing immutability
        HashMap hm1 = immutableClass1.getProperties();

        //lets modify the Object passed as argument or get from the Object
        hm1.put("test", "test");

        //check that immutable class properties are not changed
        System.out.println(immutableClass1.getProperties());
    }

}
//输出结果:创建不可变类成功
{City=San Jose, Name=Pankaj}

你可能感兴趣的:(Java基础学习笔记)