zoukankan      html  css  js  c++  java
  • 《疯狂Java讲义精粹》读书笔记8 不可变类

    =======================《疯狂Java讲义精粹》读书笔记8 ------ 不可变类========================

      当我们想创建一个实例后,要求该实例的成员不再发生改变的时候,就需要使用不可变类(immutable).

      创建自定义的不可变类,应遵守如下规则:

        · 使用private 和 final修饰该类的成员变量
        · 提供带参数构造器,用于传入参数来初始化对象的成员变量
        · 为该类提供getter方法,但不要提供setter方法
        · 如果有必要重写Object 类的hashCode和equals方法

      下面的程序试图定义一个不可变类(Person),但因为包含一个引用类型的成员,且这个引用是可变类,所以导致了Person类也变成了可变类:

    /**
    * 一个失败的不可变类
    * @author 《疯狂的Java讲义精粹》
    */
    class Name{ private String firstName; private String lastName; //构造方法 public Name(){} public Name(String firstName, String lastName){ this.firstName = firstName; this.lastName = lastName; } //getter and setter public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } } public class Person { private final Name name; //构造方法 public Person(Name name){ this.name = name; } //只提供getter方法 public Name getName(){ return name; } public static void main(String[] args) { Name n = new Name("Cocoon","Fan"); Person p = new Person(n); //将输出CocoonFanFan System.out.println(p.getName().getFirstName()+p.getName().getLastName()); //这时候依然可以改变Person对象的属性所指向的内容值,只是不能改变Person对象的属性 //p.name = null;//这里编译不能通过 p.getName().setFirstName("我的名字已经被改了!"); //将输出:我的名字已经被改了!Fan System.out.println(p.getName().getFirstName() + p.getName().getLastName()); } }

      很明显,Person对象的name的firstName已经被改了,这不符合要求创建一个不可变类的初衷。

      下面对Person类做一些修改,使其满足不可变类的要求:

    /**
     * 修改后的Person类满足不可变类的要求
     * @author 《疯狂的Java讲义精粹》
     *
     */
    class Name{
        private String firstName;
        private String lastName;
        
        //构造方法
        public Name(){}
        public Name(String firstName, String lastName){
            this.firstName = firstName;
            this.lastName = lastName;
        }
        
        //getter and setter
        public String getFirstName() {
            return firstName;
        }
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
        public String getLastName() {
            return lastName;
        }
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
        
    }
    
    public class Person {
        private final Name name;
        
        public Person (Name name){
            //设置name 为临时创建的Name 对象,该对象的firstName 和 lastName与
            //传入的name对象的firstName 和 lastName相同
            this.name = new Name(name.getFirstName(), name.getLastName());
        }
        public Name getName(){
            //返回一个匿名对象,该对象的firstName 和 lastName 与该对象里的name 的firstName
            //和lastName相同
            return new Name(name.getFirstName(),name.getLastName());
        }
        
        public static void main(String[] args) {
            Name n = new Name("Cocoon","Fan");
            Person p = new Person(n);
            
            //将输出: CocoonFanFan
            System.out.println(p.getName().getFirstName()+p.getName().getLastName());
            
            //这时候改变不了Person对象的属性了
            p.getName().setFirstName("我的名字已经被改了!");
            //将输出:CocoonFan
            System.out.println(p.getName().getFirstName() + p.getName().getLastName());
            
        }
    }

      不可变类的实例状态不可改变,可以很方便的、地被多个对象共享。如果程序要使用相同的不可变类实例,则应考虑缓存这种不可变类的实例,因为重复创建相同的对象对系统的开销会很大。如果可能,应将已经创建的不可变类的实例进行缓存

      本例将使用一个数组来作为缓存池,从而实现一个缓存实例的不可变类:

    /**
     * 缓存实例不可变类
     * @author 《疯狂Java讲义精粹》
     * @date 3/7/2013
     */
    
    class CacheImmutale {
        private static int MAX_SIZE = 10;//缓存的大小
        //穿件缓存池
        private static CacheImmutale[] cache = new CacheImmutale[MAX_SIZE];
        
        //记录缓存实例在缓存中的位置
        private static int pos = 0;
        
        private final String name;
        private CacheImmutale(String name){
            this.name = name;
        }
        public String getName(){
            return name;
        }
        
        public static CacheImmutale valueOf(String name){
            //遍历缓存对象
            for (int i = 0; i < MAX_SIZE; i++) {
                //如果已经存在相同的缓存实例,直接返回该缓存实例
                if(cache[i] != null && cache[i].getName().equals(name)){
                    return cache[i];
                }
            }
            
            //如果缓存池已满
            if(pos == MAX_SIZE){
                //把缓存的第一个对象覆盖
                cache[0] = new CacheImmutale(name);
                pos = 1;
            } else {
                //把新创建的对象缓存起来
                cache[pos++] = new CacheImmutale(name);
            }
            return cache[pos-1];
        }
        
        //重写equals方法
        public boolean equals(Object obj){
            if(this == obj){
                return true;
            }
            if(obj != null && obj.getClass() == CacheImmutale.class){
                CacheImmutale c = (CacheImmutale)obj;
                return name.equals(c.getName());
            }
            return false;
        }
        
        //重写hashCode 方法
        public int hashCode(){
            return name.hashCode();
        }
    }
    
    
    public class TestCacheImmutale{
        public static void  main(String []args){
            CacheImmutale c1 = CacheImmutale.valueOf("Hello");
            CacheImmutale c2 = CacheImmutale.valueOf("Hello");
            
            //将输出true
            System.out.println("c1 == c2:" + (c1==c2));
        }
    }

      Java提供的java.lang.Integer类,就采用了与上面CacheImmutable类类似的处理策略,如果采用new 构造器来创建Integer对象,则每次返回全新的Integer对象,如果采用valueOf()方法来创建对象,则会缓存该方法创建的对象。应该注意的是Integer只是缓存-128~127之间的Integer 对象,例如两次通过Integer.valueOf(200);方法生成的对象就是两个不同的对象。

  • 相关阅读:
    常用正则表达式
    玉洁哥的设计模式指摘
    jquery makearray()使用
    html/css技巧总结
    json 数组 对象 xml 之间转换(待补充)
    Html5 Geolocation获取地理位置信息
    JSON.stringify 应用
    url操作一网打尽(一)
    jquery选择器
    JavaScript Window Location
  • 原文地址:https://www.cnblogs.com/CocoonFan/p/2948161.html
Copyright © 2011-2022 走看看