第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)重载构造函数

package org.github.effective.p2;

public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate; public NutritionFacts(int servingSize, int servings) {
this(servingSize, servings, 0);
} public NutritionFacts(int servingSize, int servings, int calories) {
this(servingSize, servings, calories, 0);
} public NutritionFacts(int servingSize, int servings, int calories, int fat) {
this(servingSize, servings, calories, fat, 0);
} public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) {
this(servingSize, servings, calories, fat, sodium, 0);
} public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbonhydrate) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbonhydrate;
}
}  

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

(2)JavaBeans模式

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

缺点:

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

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

(3)Builder模式

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

package org.github.effective.p2;

public class NutritionFacts2 {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate; public static class Builder {
private final int servingSize;
private final int servings;
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0; public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
} public Builder calories(int val) {
this.calories = val;
return this;
} public Builder fat(int val) {
this.fat = val;
return this;
} public Builder carbohydrate(int val) {
this.carbohydrate = val;
return this;
} public Builder sodium(int val) {
this.sodium = val;
return this;
} public NutritionFacts2 build() {
return new NutritionFacts2(this);
} } private NutritionFacts2(Builder builder) {
this.servingSize = builder.servingSize;
this.servings = builder.servings;
this.calories = builder.calories;
this.fat = builder.fat;
this.sodium = builder.sodium;
this.carbohydrate = builder.carbohydrate;
} public static void main(String[] args) {
NutritionFacts2 cocaCola = new NutritionFacts2.Builder(240, 8).calories(100).sodium(50).carbohydrate(27).build();
} }  

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

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

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

创建单例的几种方法:

(1)

public class Elvis {
public static final Elvis INSTANCE = new Elvis()
private Elvis(){}
public void m(){......}
}  

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

(2)

public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis(){}
public static Elvis getInstance(){
return INSTANCE;
} public void m() {......} }  

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

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

public enum Elvis {
INSTANCE; public void m(){.......} }  

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

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

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

public class Utility {

 private Utility() {
throw new AssertionError()
} }  

由于显式的构造器是私有的,所有不可以在该类的外部访问它,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. NHibernate 之数据操作 (第五篇)

    数据操作,在这里主要介绍INSERT.UPDATE.DELETE.我们在使用NHibernate的时候,如果只是查询数据,不需要改变数据库的值,那么是不需要提交或者回滚到数据库的. 一.INSERT ...

  2. ms_sql_server_architecture

    We have classified the architecture of SQL Server into the following parts for easy understanding − ...

  3. pca主成份分析方法

    1.应用pca的前提 应用pca的前提是,连续信号具有相关性.相关性是什么,是冗余.就是要利用pca去除冗余. 2.pca的定义 pca是一种去除随机变量间相关性的线性变换.是一种常用的多元数据分析方 ...

  4. 使用Gradle构建Android应用的渠道包

    所有做Android App的同志们应该都知道渠道包是什么,得力于Android生态的多样性,我等写Android应用的人类每次发布App都需要面对数十个市场,而为了能够采集到市场的表现数据,就必须为 ...

  5. xampp Apache Access forbidden! Error 403解决方法

    今天下载了最新的xampp,配置了一个虚拟主机,一直在报错,Access forbidden! Error 403 这很明显是服务器不允许访问文件,但是我的虚拟主机配置如下: DocumentRoot ...

  6. lumisoft邮件头不规范造成内容无法读取

    解决邮件内容为multipart,并且Param_Boundary等于null的不规范邮件内容无法读取问题,这样的邮件内容头部往往带两个或多个ContentType. 红色为自己加的,绿色为注释掉原来 ...

  7. 【云计算】Ubuntu14.04 搭建GlusterFS集群

    1.修改 /etc/hosts 所有服务节点执行(如果集群中没有DNS,可忽略此步骤): 10.5.25.37 glusterfs-1-5-25-3710.5.25.38 glusterfs-2-5- ...

  8. 正则表达式学习(PCRE)

    正则表达式是一个从左到右匹配目标字符串的模式.大多数字符自身就代表一个匹配 它们自身的模式. 1.分隔符:当使用 PCRE 函数的时候,模式需要由分隔符闭合包裹.分隔符可以使任意非字母数字.非反斜线. ...

  9. 深入分析JavaWeb Item24 -- jsp2.X自己定义标签开发进阶

    一.简单标签(SimpleTag) 由于传统标签使用三个标签接口来完毕不同的功能,显得过于繁琐.不利于标签技术的推广, SUN公司为减少标签技术的学习难度,在JSP 2.0中定义了一个更为简单.便于编 ...

  10. iPhone销售拉动 鸿海精密第一季度利润增长21%

    据美国<华尔街日报>5月15日消息,苹果公司主要代工厂鸿海精密发布,第一季度利润增长21%.主要得益于iPhone手机销量强劲以及生产效率提升. 这家全球最大的电子产品代工商近一半的收入是 ...