• 第三十九条:必要时进行保护性拷贝


    使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类就真正变成了一个不可变类,它的实例对象只有在初始化的那一种状态。

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

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

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

  • 相关阅读:
    HTML基础-第一讲
    DIV中display和visibility属性差别
    1.html+css页面设计
    Log4j中为什么设计isDebugEnabled()方法
    CI中写原生SQL(封装查询)
    codeigniter 对数据库的常用操作
    CI中PHP写法规范(不断更新)
    CI中自定义SQL查询,LIKE模糊查询的处理
    CI中REST URL含有中文怎么处理(报错:The URI you submitted has disallowed characters)
    MyISAM InnoDB 区别
  • 原文地址:https://www.cnblogs.com/wangliyue/p/4484809.html
Copyright © 2020-2023  润新知