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

    使Java使用起来如此舒适的一个因素在于,它是一门安全的语言。这意味着,它对于缓冲区溢出,数组越界,非法指针以及其他的内存破坏

    都自动免疫,而这些错误却困扰着诸如C和C++这样的不安全语言。在一门安全的语言中,在设计类的时候,可以确切的知道,无论系统的

    其他部分发生什么事情,这些类的约束都可以保持为真。对于那些“把所有的内存当成一个巨大的数组来看待”的语言来说,这是不可能的。

    有一种情况进行保护性拷贝就是需要的:

    public  class   Period

    {

             private   final   Date   startTime;

             private   finale  Date   endTime;

             public   Period(Date  startTime , Date  endTime)

            {

                   if(startTime.compareTo(endTime) > 0)

                   { throw   new  IllegalArgumentException(“startTime  after  endTime !”);  }

                    this.startTime = startTime;

                    this.endTime  = endTime;

            }

            pubilc   Date   start()

            {  return   this.startTime ; }

            public   Date  end()

            { return  this.endTime  ; }

    }

    这个类貌似是一个不可变类 ,因为startTime和endTime域都是final的,但是它并不是一个严格的不可变类,因为Date类并不是一个不可变类。

    如果客户端这样使用我们定义的Period类 :

    Date  startTime   =  new Date();

    Date  endTime   = new  Date();

    Period  per =  new  Period(startTime ,  endTime );

    endTime.setYear(78);

    本来我们希望Period是一个不可变类,只有初始化的那一种状态,但是由于Date类是一个可变类,我们获取了final  Date  startTime域所引用

    的那个对象,而这个对象是一个Date类,我们就可以改变这个对象的状态,从而导致Period的实例对象中的状态进行了改变。

    这个时候我们对于构造器进行保护性拷贝 :

    public   Period(Date   startTime , Date  endTime )

    {

          this.startTime  =  new Date (startTime.getTime());

          this.endTime   =  new  Date(endTime.getTime());

         if(this.startTime.compareTo(this.endTime)  >  0)

        { 

              throw   new    IllegalArgumentException(“startTime  after   endTime !”);

        }

    }

    这样在使用上面那样的客户端代码时,在对endTime对象改变状态时,就不会影响到Period类的实例对象状态了。

    但是如果客户端使用这样的代码   per.start().setYear(78);   这样同样破坏了per对象的状态。

    那么对于返回实例对象域的start(),end()方法也应该使用保护性拷贝。

    public  Date   start()

    {

          return   new  Date(startTime.getTime());

    }

    public  Date  end()

    {

          return  new   Date(endTime.getTime());

    }

    这样,我们定义的Period类就真正变成了一个不可变类,它的实例对象只有在初始化的那一种状态。

    使用保护性拷贝是为了我们的代码更加健壮,考虑客户端代码的种种恶意破坏。

    一般情况,当我们想要定义一个不可变类,但是这个类的域的类型确实一个可变类,那么我们在定义构造器的时候是需要进行保护性拷贝的。

    而且记住对于参数有效性的检验应该在保护性拷贝之后。

  • 相关阅读:
    php 上传大文件主要涉及配置upload_max_filesize和post_max_size两个选项
    Linux 文件系统IO性能优化【转】
    MOOC Linux内核之旅小结【转】
    python实战===教你用微信每天给女朋友说晚安【转】
    wxpy: 用 Python 玩微信【转】
    AMBA总线协议AHB、APB、AXI对比分析【转】
    高手进阶,终极内存技术指南——完整/进阶版 II (转)【转】
    ARMCC和GCC编译ARM代码的软浮点和硬浮点问题 【转】
    程序员必知之浮点数运算原理详解【转】
    Hash算法【转】
  • 原文地址:https://www.cnblogs.com/wangliyue/p/4484809.html
Copyright © 2011-2022 走看看