第1条:考虑用静态工厂方法替代构造器
如下方法将boolean基本类型值转换为了一个Boolean对象引用
public static Boolean valueOf(boolean b){
return b ?Boolean.TRUE:Boolean.FALSE;
}
静态工厂方法与构造器相比的第一大优势:它们会有名称
第二大优势(重点):不必在每次调用它们的时候都创建一个新对象。静态工厂方法能够为重复的调用返回相同的对象,这样有助于类总能严格控制在某个时刻哪些实例应该存在
第三大优势:它们可以返回原返回类型的任何子类型的对象
第四大优势在于:在创建参数化类型实例的时候,它们让代码变得更加简洁。例如HashMap提供了这个静态工厂
public static <K,V> HashMap<K,V> newInstance(){
return new HashMap<K,V>();
}
如下为静态工厂方法的一些惯用名称
1,valueOf 它实际上是类型转换方法
2,getInstance 返回的实例通过方法的参数来描述
3,newInstance 确保返回的每个实例与其他实例不同
第2条 遇到多个构造器参数时要考虑用构建器
Bulilder模式:不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器得到一个builder对象。然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数。最后调用无参的build方法来生成不可变的对象。这个builder是它构建的类的静态成员类。
下面为实例
public class Demo{
private final int a;
private final int b;
public static class Builder{
private final int a;
private final int b;
public Builder(int a,int b){
this.a = a;
this.b = b;
}
public Demo bulid(){
return new Demo(this);
}
}
private Demo(Builder builder){
a = builder.a;
b = builder.b;
}
}
如果类的构造器或者静态工厂中有多个参数,设计这种类时Builder模式是个不错的选择。
第3条 用枚举类强化Singleton属性
public enum Elivis{
INSTANCE;
public void leaveTheBuilding(){....
}
}
这种方法更加简洁,无偿提供了序列化机制,防止多次实例化。
第4条 通过私有构造器强化不可实例化的能力
在我们日常开发工具类时,不希望被实例化,这样的实例对它没有任何意义。然而,在缺少显示构造器的情况下,编译器会自动提供一个公有的,无参的缺省构造器。这种情况我们只要让这个类包含私有构造器,它就不能被实例化了。
public class UtilityClass{
private UtilityClass(){
…
}
}
第5条 避免创建不必要的对象
直接上例子。。。
public class Person {
private final Date birthDate;
public boolean isBabyBoomer(){
//Unnecessary allocation of expensive object
Calendar a = Calendar.getInstance(TimeZone.get("GMT"));
a.set(....);
Date startDate = a.getTime();
a.set(...);
Date endDate = a.getTime();
return birthDate.compareTo(startDate) >= 0 &&
birthDate.compareTo(boomEnd) < 0;
}
}
这个实例每次被调用的时候都会新建一个Calendar,一个TimeZone和两个Date。这是不必要的。下面的版本用静态的初始化器提升了效率
class Person{
private final Date birthDate;
private static final Date START_DATE;
private static final Date END_DATE;
static{
Calendar a = Calendar.getInstance(TimeZone.get("GMT"));
a.set(...);
START_DATE = a.getTime();
a.set(...);
END_DATE = a.getTime();
}
public boolean isBabyBoomer(){
return birthDate.compareTo(START_DATE) >= 0 &&
birthDate.compareTo(END_DATE) < 0;
}
}
改进后的代码只在初始化的时候创建这些类的时候实例化一次,而不是每次调用isBabyBoomer的时候都创建这些实例。如果方法被频繁的调用,将会显著地提高性能。
java1.5发行版本中,有一种创建多余对象的新方法,称作自动装箱,它允许程序员将基本类型和装箱基本类型混用,按需要自动装箱和拆箱。
上例子,哈哈哈
public static void main(String[] args){
Long sum = 0L;
for(long i = 0;i < Integer.MAX_VALUE;i++){
sum += i;
}
}
这段程序算出的答案是正确的,但是效率低。就因为变量sum被声明为Long而不是long.
结论:要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。
第6条 消除过期对象的引用 (阿西吧。。这章没怎么看懂)
先上一个简单的栈实现的例子
public class Stack{
private object[] elements;
private ine size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack(){
elements = new Object[DEFAULT_INITIAL_CAPACITY ];
}
public void push(Object e){
ensureCapacity();
elements [size++] = e;
}
public void pop(){
if(size == 0){
throw new EmptyStackException();
}
return elements[--size];
}
public void ensureCapacity(){
if(elements.length == size){
elements = Arrays.copyOf(elements,2*size + 1);
}
}
}
这段程序哪里发生了内存泄漏呢?如果一个栈先是增长然后再收缩,那么栈中弹出来的对象将不会被当作垃圾回收,即使程序不再使用这些对象。because栈内部维护着对这些对象的过期引用。如果一个对象引用被无意识的保留起来了,垃圾回收机制不仅不会回收这个对象,也不会处理被这个对象的所有其他对象。
修复方法:一旦对象引用过期,清空这些引用即可。
一般而言,只要类是自己管理内存, 程序员就该警惕内存泄漏问题。
。。。。。。(这章不好理解啊。。。。。先略。。。)
第7条 避免使用终结方法(阿西吧。。。只是理解了一部分。。。心塞)
终结方法的一个缺点在于不能保证会被及时的执行。
及时的执行终结方法正是垃圾回收算法的一个主要功能。
结论:不应该依赖终结方法来更新重要的持久状态。
使用终结方法有一个非常严重的性能损失。
如果类的对象中封装的资源确实需要终止,这个时候只需要提供一个显示的终结方法。并要求该类的客户端在每个实例不再有用的时候调用这个方法。其中,该实例必须记录下自己是否已经被终止。