Effective Java 读书笔记(1)

2017-08-28  本文已影响22人  Lin_Shao

创建和销毁对象


第一条:考虑用静态工厂方法代替构造器

当该类需要返回不同的实例(子类实例),或者唯一一个实例(单例)时,应考虑用静态工厂方法代替构造器。
静态工厂方法的一些惯用名称:


第二条:遇到多个构造器参数时要考虑用构建器

当创建对象面临多个可选参数时(即,构造器有多个可选的参数),有以下三种方案:


第三条:用私有构造器或者枚举类型强化Singleton属性

实现Singleton有以下三种方法:

public class FirstSingleton {
    public String message;
    public static final FirstSingleton INSTANCE = new FirstSingleton();

    private FirstSingleton(){
        message = "Hello World! First Singleton!";
    }
}

由于缺少公有的或者受保护的构造器,所以保证了单例的全局唯一性。

注意:享有特权的客户端可以借助AccessibleObject.setAccessibe方法,通过反射机制调用私有构造器。如果需要抵御这种攻击,可以修改私有构造器,使其在构造第二个实例时抛出异常。

public class SecondSingleton {
    public String message;
    private static final SecondSingleton INSTANCE  = new SecondSingleton();
    private SecondSingleton(){
        message = "Hello World! Second Singleton!";
    }
    public static SecondSingleton getInstance(){
        return INSTANCE;
    }
}

对于静态方法getInstance的所有调用,都会返回同一个对象引用(上述注意依然使用)。
公有域方法的主要好处在于,组成类的成员的声明很清楚第表明了这个类是一个Singleton:公有的静态域是final的,所以该域将总是包含相同的对象引用。

对于以上两种方法,在序列化时,仅仅在声明中加上implements Serializable是不够的。为了维护并保证Singleton,必须声明所有的实例域都是瞬时的(transient)的,并提供一个readResove实例。否则,每次反序列化一个实例时,都会创建一个新的实例:

    private Object readResolve(){
        return INSTANCE;
    }
    public enum ThirdSingleton {
    INSTANCE;
    public String message = "Hello World! Third Singleton!";
}

这种方法在功能上与公有域方法相近,但是其更加简洁,无偿地提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击时。单元素的枚举类型已经成为实现Singleton的最佳方法。


第四条:通过私有化构造器强化不可实例的能力

有时候,我们需要编写只包含静态方法和静态域的类。这些工具类不希望被实例化,实例对它没有任何意义。这个时候,我们需要私有化构造器,防止其在无意间被实例化。


第五条:避免创建不必要的对象

一般来说,最好能重用对象而不是每次需要 的时候就创建一个相同功能的新对象。


第六条:消除过期的对象引用

在支持垃圾回收的语言中,内存泄漏是很隐蔽的,称之为“无意识的对象保持(unintentional object retention)“更为恰当。如果一个对象被无意识保留起来,那么垃圾回收机制不仅不会去处理这个对象,而且不会处理这个对象所引用的所有其他对象,久而久之会对性能造成潜在的重大影响。

这种问题一般出现在堆、栈、数组、链表等数据结果在pop对象时没有消除引用,如size--;
这种问题的解决方法很简单,一旦对象过期,清空这些引用即可stack[size--] = null;

内存泄漏的常见来源:


第七条:避免使用终结方法

终结方法(finalizer)通常是不可预测的,也是很危险的。
终结方法通常在垃圾回收机制回收对象时负责执行,其执行时间取决于jvm设计、配置以及程序执行过程。而且,java规范并不保证终结方法一定会被执行。还有一点,使用终结方法会带来严重的性能损耗。
若一个对象需要在其终结时进行某些动作,可以考虑使用显式终结动作,并要求所有客户端在结束该实例时调用该方法,例如InputStream接口的close方法
终结方法的合法用途:

上一篇 下一篇

猜你喜欢

热点阅读