Effective Java 读书笔记(1)

创建和销毁对象


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

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

  • valueOf 返回的实例与参数有相同的值,相当于类型转换
  • of valueOf的简化
  • getInstance 返回的实例是通过参数类描述的,但一般不具有与参数同样的值。对于Singleton来说,无参数,返回唯一一个实例。
  • newInstance 类似于getInstance,但每次返回新的实例
  • getType 在工厂方法处于不同的类时使用,Type指返回类型的类型
  • newType 同上

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

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

  • 重叠构造器模式
    根据参数的不同组合,编写多个签名不同的构造器或静态工厂方法。优点:线程安全,参数组合少时简单;缺点:当参数量很大,且其组合很多时,代码编写麻烦且可读性差
  • JavaBean模式
    调用一个构造器类创建对象并设置必要的参数,再通过setter方法类设置每个可选参数。优点:实例简单,代码简洁,可扩展性强。缺点:构造过程被分为多个调用方法,难以保证一致性,(多线程)易出错难调试;无法实例化一个不可变对象(致命)
  • Builder模式
    不直接生成想要的对象,而是先用必要的参数实例化一个builder,再用setter方法设置每个可选参数,最后调用无参的build方法来生成不可变的对象。既能保证重叠构造器模式的安全性,也能保证像JavaBean一样简单可读

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

实现Singleton有以下三种方法:

  • 将构造器私有化,将实例设为公有的静态final成员。私有构造器只被调用一次,用来实例化单例:
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的最佳方法。


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

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


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

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

  • 重用不可变对象:如果对象是不可变的,它就始终可以被重用(单例模式、String对象池)
  • 重用已知不会被修改的可变对象。创建某些对象的成本是十分昂贵的,且其在创建之后,其值一般不会改变,此时我们可以考虑重用这个对象已减少创建成本。
  • 使用适配器(适配器是指这样一个对象:它把功能委托给一个后备对象,从而为后备对象提供一个可以替代的接口)。如Map类的KeySet方法,它返回一个Set对象。对于一个Map而言,它的key是可变的,但是keySet对象是唯一的,只是其内容会发生变化。
  • 优先使用基本类型而不是自动装箱基本类型,当心无意识的自动装箱。

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

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

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

内存泄漏的常见来源:

  • 类自己管理内存。当我们需要写自己管理内存 的类时,如手动实现一个stack,应谨记一旦元素不需要用到,要立即释放(消除引用),以便垃圾回收机制能及时回收。
  • 缓存。缓存中的对象极易被遗忘。-> 使用WeakHashMap代表缓存
  • 监听器及其他回调。如果你实现了一个API,客户端在这个API中注册回调,却没有显式取消注册,那么除非你采取某些动作,否则它们就会被积聚。确保回调立即被当做立即回收的最佳方法是只保存它们的弱引用。

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

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

  • 充当显式终结方法的“安全网(safety net)。
  • 终结非关键的本地资源(一般指本地对等体native peer),即本地对象。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容