第1章

如何最有效地使用Java程序设计语言机器基本类库:java.lang,java.util,java.util.concurrent和java.io。

Sun JDK1.6_05版本

第2章 创建和销毁对象

创建和销毁对象:何时以及如何创建对象,何时以及如何避免创建对象,如何确保它们能够适时地销毁,以及如何管理对象销毁之前必须进行的各种清理动作。

1. 考虑用静态工厂方法代替构造器

为了让客户端获取对象的一个实例,最常用的方法就是提供一个公共的构造器,还有另一种方法:类可以提供一个公共的静态工厂方法(static factory method),它只是一个返回类的实例的静态方法。

注意静态工厂方法与设计模式中的工程方法模式不同。

优点

  • 静态工厂方法与构造器不同的第一大优势在于,它们又名称:如果构造器的参数本身没有确切的描述正被返回的对象,那么具有适当名称的静态工厂会更容易使用,产生的客户端代码也更易于阅读。例如:BigInteger(int, int, Random)返回的BigInteger可能为素数,如果用名为BigInteger.probablePrime的静态工厂方法来表示,显得更为清楚。
  • 静态工厂方法与构造器不同的第二大优势在于,不必再每次调用它们的时候都创建一个新对象:不可变类可以使用预先创建好的实例,或则将创建好的实例缓存。
  • 静态工厂方法与构造器不同的第三大优势在于,它们可以返回原返回类型的任何子类型的对象:选择返回对象的类时就有更大的灵活性。例如Java Collections Framework的集合接口有32个便利实现,分别提供了不可修改的集合,同步集合等。几乎所有这些实现都通过静态工厂方法在不可实例化的类java.util.Collections中导出,所有返回对象的类都是非公有的。
  • 静态工厂方法的第四大优势在于,在创建参数化类型实例的时候,它们使代码变得更加简洁。

缺点

  • 类如果不含公有的或受保护的构造器,就不能被子类化。
  • 它们与其他的静态方法实际上没有任何区别。静态工厂方法的一些惯用名称:valueOf,of,getInstance,newInstance,getType,newType

总结:静态工厂更加合适,因此切忌第一反应就是提供公有的构造器,而不先考虑静态工厂。

2. 遇到多个构造器参数时要考虑用构造器

静态工厂和构造器有个共同的局限性:他们都不能很好地扩展到大量的可选参数。

面对很多参数的类,如何创建类?

(1)重载构造函数

  1. package org.github.effective.p2;
  2.  
  3. public class NutritionFacts {
  4. private final int servingSize;
  5. private final int servings;
  6. private final int calories;
  7. private final int fat;
  8. private final int sodium;
  9. private final int carbohydrate;
  10.  
  11. public NutritionFacts(int servingSize, int servings) {
  12. this(servingSize, servings, 0);
  13. }
  14.  
  15. public NutritionFacts(int servingSize, int servings, int calories) {
  16. this(servingSize, servings, calories, 0);
  17. }
  18.  
  19. public NutritionFacts(int servingSize, int servings, int calories, int fat) {
  20. this(servingSize, servings, calories, fat, 0);
  21. }
  22.  
  23. public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) {
  24. this(servingSize, servings, calories, fat, sodium, 0);
  25. }
  26.  
  27. public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbonhydrate) {
  28. this.servingSize = servingSize;
  29. this.servings = servings;
  30. this.calories = calories;
  31. this.fat = fat;
  32. this.sodium = sodium;
  33. this.carbohydrate = carbonhydrate;
  34. }
  35. }  

重载构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且仍然较难阅读。

(2)JavaBeans模式

调用一个无参构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数。

缺点:

因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。

JavaBean模式阻止了把类做成不可变的可能。

(3)Builder模式

不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造前期得到一个builder对象,然后客户端在Builder对象上调用类似于setter的方法,来设置每个相关的可选参数,最后客户端调用无参的build方法来生成不可变的对象。这个Builder是它构建的类的静态成员类。

  1. package org.github.effective.p2;
  2.  
  3. public class NutritionFacts2 {
  4. private final int servingSize;
  5. private final int servings;
  6. private final int calories;
  7. private final int fat;
  8. private final int sodium;
  9. private final int carbohydrate;
  10.  
  11. public static class Builder {
  12. private final int servingSize;
  13. private final int servings;
  14. private int calories = 0;
  15. private int fat = 0;
  16. private int sodium = 0;
  17. private int carbohydrate = 0;
  18.  
  19. public Builder(int servingSize, int servings) {
  20. this.servingSize = servingSize;
  21. this.servings = servings;
  22. }
  23.  
  24. public Builder calories(int val) {
  25. this.calories = val;
  26. return this;
  27. }
  28.  
  29. public Builder fat(int val) {
  30. this.fat = val;
  31. return this;
  32. }
  33.  
  34. public Builder carbohydrate(int val) {
  35. this.carbohydrate = val;
  36. return this;
  37. }
  38.  
  39. public Builder sodium(int val) {
  40. this.sodium = val;
  41. return this;
  42. }
  43.  
  44. public NutritionFacts2 build() {
  45. return new NutritionFacts2(this);
  46. }
  47.  
  48. }
  49.  
  50. private NutritionFacts2(Builder builder) {
  51. this.servingSize = builder.servingSize;
  52. this.servings = builder.servings;
  53. this.calories = builder.calories;
  54. this.fat = builder.fat;
  55. this.sodium = builder.sodium;
  56. this.carbohydrate = builder.carbohydrate;
  57. }
  58.  
  59. public static void main(String[] args) {
  60. NutritionFacts2 cocaCola = new NutritionFacts2.Builder(240, 8).calories(100).sodium(50).carbohydrate(27).build();
  61. }
  62.  
  63. }  

总结:如果累的构造器或静态工厂中具有多个参数,这几这种类时,Builder模式就是不错的选择,特别是当大多数参数都是可选的时候。

3. 用私有构造器或枚举类型强化Singleton属性

Singleton指仅仅被实例化一次的类,通常被用来代表那些本质上唯一的系统组件。

创建单例的几种方法:

(1)

  1. public class Elvis {
  2. public static final Elvis INSTANCE = new Elvis()
  3. private Elvis(){}
  4. public void m(){......}
  5. }  

但是享有特权的客户端可以借助AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。

(2)

  1. public class Elvis {
  2. private static final Elvis INSTANCE = new Elvis();
  3. private Elvis(){}
  4. public static Elvis getInstance(){
  5. return INSTANCE;
  6. }
  7.  
  8. public void m() {......}
  9.  
  10. }  

为了利用其中一种方法实现的Singleton类变成是可序列号的。仅仅在声明上加上implements Serializble是不够的,为了维护并保证Singleton,必须声明所有实例域都是transient的,并提供一个readResolve方法。否则每次反序列化一个序列化的实例时,都会创建一个新的实例。

(3)包含单个元素的枚举类型

  1. public enum Elvis {
  2. INSTANCE;
  3.  
  4. public void m(){.......}
  5.  
  6. }  

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

4. 通过私有构造器强化不可实例化的能力

工具类不希望别实例化,实例对它没有任何意义。

  1. public class Utility {
  2.  
  3. private Utility() {
  4. throw new AssertionError()
  5. }
  6.  
  7. }  

由于显式的构造器是私有的,所有不可以在该类的外部访问它,AssertionError不是必须的,但是它可以避免不小心在类的内部调用构造器。保证该类在任何情况下都不会被实例化。

5. 避免创建不必要的对象

一般来说,最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。如果对象是不可变的(immutable),就始终可以被重用。

6. 消除过期的对象引用

清空对象引用应该是一种例外,而不是一种规范行为。消除过期引用最好的方法是让包含该引用的变量结束其生命周期。

7. 避免使用终结方法

finalizer方法通常是不可预测的,也是很危险的,一般情况下是不必要的。

x.参考文档

《Effective Java中文版 第2版》

Effective Java-第二章的更多相关文章

  1. 如何创建和销毁对象(Effective Java 第二章)

    最近有在看Effective Java,特此记录下自己所体会到的东西,写篇博文会更加的加深印象,如有理解有误的地方,希望不吝赐教. 这章主题主要是介绍:何时以及如何创建对象,何时以及如何避免创建对象, ...

  2. [Effective Java]第二章 创建和销毁对象

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  3. 对于所有对象都通用方法的解读(Effective Java 第二章)

    这篇博文主要介绍覆盖Object中的方法要注意的事项以及Comparable.compareTo()方法. 一.谨慎覆盖equals()方法 其实平时很少要用到覆盖equals方法的情况,没有什么特殊 ...

  4. “全栈2019”Java第二章:安装JDK11(Windows)

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 文章原文链接 "全栈2019"Java第二章:安装JDK11(Windows) 下一 ...

  5. Effective Java 第二版 Enum

    /** * Effective Java 第二版 * 第30条:用enum代替int常量 */ import java.util.HashMap;import java.util.Map; publi ...

  6. Java 第二章 变量

    第二章 变量 变量称为:是计算机语言中能储存计算机结果或能表示值抽象概念 .变量可以通过变量名访问 int money ; //变量 money=1000; //赋值 int money=1000: ...

  7. Java第二章----对象和类

    从第一章到第二章整整隔了一个月的时间,这速度也是慢的无语了.因为这个月负责开发公司一个SaaS类型APP,忙的昏天暗地终于上线了,这才有时间写个博客.本章还是以概念为主,有点枯燥重在理解. 第一节:对 ...

  8. Java 第二章 变量、数据类型和运算符

    第二章      变量.数据类型和运算符 什么是变量: 变量代表一块内存区域,变量类型不一样,这一块内存的大小也不一样. #在编程语言里面,你可以通过定义变量,向内存里添加数据或者修改内存已有的数据. ...

  9. 《Effective Java 第二版》读书笔记

    想成为更优秀,更高效程序员,请阅读此书.总计78个条目,每个对应一个规则. 第二章 创建和销毁对象 一,考虑用静态工厂方法代替构造器 二, 遇到多个构造器参数时要考虑用builder模式 /** * ...

  10. Effective java第一章引言

    菜鸟一枚,开始读第一本书<Effective Java>(第二版)~ 看引言就有好多名词不懂(>_<) 导出的API由所有可在定义该API的包之外访问的API元素组成.一个包的 ...

随机推荐

  1. C\C++宏大全

    一.标准预定义宏The standard predefined macros are specified by the relevant language standards, so they are ...

  2. Linux 内核中的 GCC 特性

    https://www.ibm.com/developerworks/cn/linux/l-gcc-hacks/ GCC 和 Linux 是出色的组合.尽管它们是独立的软件,但是 Linux 完全依靠 ...

  3. 记一个有趣的Java OOM!

    原文:https://my.oschina.net/u/1462914/blog/1630086 引言 熟悉Java的童鞋,应该对OOM比较熟悉.该类问题,一般都比较棘手.因为造成此类问题的原因有很多 ...

  4. 修改activeMQ端口号

    原文:http://jingyan.baidu.com/article/3ea51489fba6a152e61bbacc.html 修改TCP 61616端口 打开您的mq安装目录 请看下图 如下图所 ...

  5. Dependent Parameters in Concurrent Program using Special Value Set

    Dependent Parameters in Oracle Applications Requirement: Say there is a concurrent program that lets ...

  6. Gulp新手入门教程

    Gulp 是一个自动化工具,前端开发者可以使用它来处理常见任务: 搭建web服务器 文件保存时自动重载浏览器 使用预处理器如Sass.LESS 优化资源,比如压缩CSS.JavaScript.压缩图片 ...

  7. 关于TagHelper的那些事情——TagHelper的基本知识

    概要 TagHelper是ASP.NET 5的一个新特性.也许在你还没有听说过它的时候, 它已经在技术人员之间引起了大量讨论,甚至有一部分称它为服务器控件的回归.实际上它只不过是一个简化版本,把HTM ...

  8. Delphi 对象模型学习笔记(转)

    摘要     Borland Object Pascal 对象模型(现在已经正是命名为 Delphi 语言)与其他 OOP 语言一样,都提供了一些基础服务: 如对象创建服务.对象释放服务.对象识别服务 ...

  9. Fragment与Activity传递数据

    MainActivity如下: package cc.testsimplefragment0; import android.os.Bundle; import android.app.Activit ...

  10. [Python爬虫] 之十一:Selenium +phantomjs抓取活动行中会议活动信息

    一.介绍 本例子用Selenium +phantomjs爬取活动行(http://www.huodongxing.com/search?qs=数字&city=全国&pi=1)的资讯信息 ...