effective Java 学习笔记(三)

来源:互联网 发布:ipad数据恢复 编辑:程序博客网 时间:2024/05/21 19:28

 

第三条      通过私有构造函数强化不可实例化的能力
只包含静态方法和静态域的类,可以把操作在原语类型的值或者数组类型上的相关方法组织起来,如java.lang.Math或者java.util.Arrays,也可以把操作在实现特定接口的对象上的方法组织起来,如java.util.Collections。我们还可以利用这种类把操作在final类上的方法组织起来,以取代扩展该类的做法。
这样的工具类(utility class)不希望被实例化,而在缺少显示构造函数的情况下,编译器会自动提供一个公有的、无参默认构造函数。防止它被实例化的方法是,让这个类包含单个显式的私有构造函数。在使用的时候,最好对构造函数的作用增加一些注释。
这样使用的副作用是使得一个类不能被子类化。所有的构造函数都必须要调用一个可访问的朝类构造函数,无论显示地或隐式地调用,这种情况下,子类没有可访问的构造函数来调用了。
 
 
第四条      :避免创建重复的对象
重复使用同一个对象,而不是每次需要的时候就创建一个功能上等价的新对象。如果一个对象是非可变的(immutable),那么它总是可以被重用。
String s = new String(“silly”);
该句每次被执行都创建一个新的String实例,”silly”本身就是一个String实例。
改进版本: String s = “No longer silly”;
该版本只使用一个String实例,而且对于所有在同一个虚拟机中运行的代码,只要它们包含相同的字符串字面常量,则该对象就会被重用。
对于同时提供了静态工厂方法和构造函数的非可变类,通常可以利用静态工厂方法而不是构造函数,以避免创建重复的对象。
除了重用非可变的对象外,对于已知不会被修改的可变对象,也可以重用他们。
         publicclass Person {
    privatefinal Date birthDate;
    public Person(Date birthDate){
       this.birthDate = birthDate;
    }
   
    publicboolean isBabyBoomer(){
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
       gmtCal.set(1946, Calendar.JANUARY,1,0,0,0);
       Date boomStart = gmtCal.getTime();
       gmtCal.set(2008, Calendar.JANUARY,1,0,0,0);
       Date boomEnd = gmtCal.getTime();
       returnbirthDate.compareTo(boomStart) >=0 &&
              birthDate.compareTo(boomEnd)<0;
    }
}
         这些Calendar,TimeZone和两个Date一般不会被修改,但每次isBabyBoomer被调用的时候,都会创建他们。下面的代码提高了效率:
publicclass Person {
    privatefinal Date birthDate;
    public Person(Date birthDate){
       this.birthDate = birthDate;
    }
   
    privatestaticfinal Date BOOM_START;
    privatestaticfinal Date BOOM_END;
   
    static{
       Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
       gmtCal.set(1946, Calendar.JANUARY,1,0,0,0);
       BOOM_START = gmtCal.getTime();
       gmtCal.set(2008, Calendar.JANUARY,1,0,0,0);
       BOOM_END= gmtCal.getTime();
    }
    publicboolean isBabyBoomer(){
       returnbirthDate.compareTo(BOOM_START) >=0 &&
              birthDate.compareTo(BOOM_END)<0;
    }
}
如果isBabyBoomer方法被频繁调用,则将会带来显著的性能提高。但如果该方法不会被调用,则没有必要初始化BOOM_STARTBOOM_END域。
 
         并不是所有的对象都能够重用,考虑适配器的情形。适配器:把功能委托给后面的一个对象,从而为后面的对象提供一个可选的接口。由于适配器出来后面的对象之外,没有其他的状态信息,所以针对某个给定对象的特定适配器而言,它不需要创建多个适配器实例。

         小对象的创建和回收是廉价的,所以通过创建附加的对象以使程序更清晰,简洁,功能强大也是好事。反之,滥用对象池(object pool)来避免对象的创建是不明智的,除非池中的对象是非常重量级的,比如数据库连接池。一般而言,维护对象池会把代码弄乱,增加内存占用(footprint,并且还损害性能。 

原创粉丝点击