zoukankan      html  css  js  c++  java
  • 第39条:必要时进行保护性拷贝

    Java是一门安全的语言,但是如果不采取措施,还是无法保证安全性。假设类的客户端会尽其所能来破坏类的约束条件,因此必须保护性地设计程序。

    考虑下面的类,声称表示一段不可变的时间周期:

    import java.util.Date;
    
    public final class Period {
        private final Date start;
        private final Date end;
        
        public Period(Date start, Date end) {
            if(start.compareTo(end) > 0)
                throw new IllegalArgumentException(start + " after " + end);
            this.start = start;
            this.end = end;
        }
        
        public Date start() {
            return start;
        }
        
        public Date end() {
            return end;
        }
    }

    因为Date本身是可变的,因此很容易违反起始时间不能在结束时间之后的约束。

    Date start = new Date();
    Date end = new Date();
    Period p = new Period(start, end);
    end.setYear(78);//改变了终止时间,破坏类的约束条件

    为保护Period实例的内部信息被破坏,对构造器的每个可变参数进行保护性拷贝,使用备份对象作为Period实例的组件,而不使用客户端传入的参数。

    public Period(Date start, Date end) {
        this.start = new Date(start.getTime());
        this.end = new Date(end.getTime());
        if(this.start.compareTo(this.end) > 0)
            throw new IllegalArgumentException(start + " after " + end);
    }

    保护性拷贝在参数有效性检查之前,这样做可以避免在多线程环境中,参数有效性通过后,从另外一个线程改变参数,使得参数有效性的检测失效。

    不使用clone方法进行保护性拷贝的原因是Date是非final的,不能保证clone方法一定返回Date对象,它可能会返回转么处于恶意的不可信子类的实例。

    进行了上面的工作后,改变Period实例仍有可能,因为它的访问方法提供了对其可变内部成员的访问能力:

    Date start = new Date();
    Date end = new Date();
    Period p = new Period(start, end);
    p.end().setYear(78);

    改变访问方法,返回可变内部域的保护性拷贝:

    public Date start() {
        return new Date(start.getTime());
    }
        
    public Date end() {
        return new Date(end.getTime());
    }

    采用新构造器和新访问方法后,Period真正地是不可变的了,不管程序员多么恶意和不合格,都绝对不会违反周期起始时间大于结束时间的约束。访问方法与构造器不同,在进行保护性拷贝的时候允许使用clone方法,因为Period内部Date的对象一定是Date,而不可能是某个不可信的子类。

    只要有可能,应该使用不可变的对象作为对象内部组件,这样不必为保护性拷贝操心。在Period例子中,使用Date.getTime()返回的基本类型作为内部的时间表示法,就不需要进行保护性拷贝了。

    如果类具有从客户端得到或者返回客户端的可变组件,类就必须保护性地拷贝这些组件,如果拷贝成本受到限制,并且类信任调用者不会修改内部组件,不进行保护性拷贝也是可以的,类的文档必须清楚说明这一点。

  • 相关阅读:
    learnyou 相关网站
    hdu 3038 How Many Answers Are Wrong
    hdu 3047 Zjnu Stadium 并查集高级应用
    poj 1703 Find them, Catch them
    poj 1182 食物链 (带关系的并查集)
    hdu 1233 还是畅通工程
    hdu 1325 Is It A Tree?
    hdu 1856 More is better
    hdu 1272 小希的迷宫
    POJ – 2524 Ubiquitous Religions
  • 原文地址:https://www.cnblogs.com/13jhzeng/p/5743747.html
Copyright © 2011-2022 走看看