一、考虑用静态工厂方法替代构造函数

代表实现:java.util.Collection Framework

Boolean类的简单例子:

public static Boolean valueOf (boolean b){
return(b ? Boolean.TRUE: Boolean.FALSE);
}

优点:

1、与构造函数不同,静态工厂方法具有名字。

一个类看起来需要多个构造函数,并且它们的运行特征相同,应考虑使用静态工厂方法来替代其中一个或多个构造函数,并且要慎重选择它们的名字以明显标示他们的不同。

2、与构造函数不同,他们每次调用的时候,不要求非得创建一个新的对象。

当一个程序要频繁的创建相同的对象,并且创建对象的代价是昂贵的,这项技术可以极大地提高性能。

3、与构造函数不同,它们可以返回一个原返回类型的子类型的对象。

缺点:

1、类如果不含公有的或者受保护的构造函数,就不能被继承。

2、它们与其他的静态方法没有任何区别。

使用静态工厂方法要遵循命名习惯,其中两个已经很流行了

valueOf : 非常有效的类型转换符

getInstance : 返回实例,对于单例模式返回唯一的实例。

结论:构造函数和静态工厂要合理选择使用。

二、使用私有构造函数强化singleton属性

实现singleton有两种方法,这两种方法都要把构造函数保持为私有的,并且提供一个静态成员,以便能够允许客户访问该类的唯一实例

1、带有公有final域的方法

// Singleton with final field
public class Elvis{
public static final Elvis INSTANCE=new Elvis(); private Elvis(){ ……
}
……//Remained omitted
}

2、静态工厂方法

// Singleton with static factory
public class Elvis{
private static final Elvis INSTANCE=new Elvis(); private Elvis(){ ……
}
public static Elvis getInstance(){
return INSTANCE;
}
……//Remained omitted
}

如果确定永远是一个singleton,用第一种方法是有意义的,如果保留余地,让以后可以修改,使用第二种方法比价好。为了使一个singleton方法是可以序列化(serializable)的,仅仅在声明中加上"implements Serializable"是不够的。为了维护singleton性,必须加上一个readResolve方法,否则的话一个序列化的实例在反复序列化的时候,都会导致创建一个新的实例。为了防止这种情况在readResolve方法:

// readResolve 方法保持单例属性
private Object readResolve() throws ObjectStreamException{
/**
*返回真正的Elvis,让垃圾收集器注意假冒的Elvis
*/
}

三、通过私有构造函数强化不可实例化的能力

将一个类包含单个显示的私有构造函数,则它就不可以被实例化了:

//不可实例化的实体类
public class UtilityClass {
//不能实例化的抑制默认构造函数
private UtilityClass(){
//该构造函数将永远不能被调用
}
……//其余的省略
}

四、避免创建重复的对象

当你重用一已有对象的时候,请不要创建新的对象,而同样的,当你创建一个新的对象的时候,请不要重用一个已有对象。在提倡使用保护行拷贝的场合,因重用一个对象儿招致的代价要远远大于因创建重复对象而招致的代价。在要求保护性拷贝的情况下却没有实施保护性拷贝,将会导致错误和安全漏洞;而不必要的创建对象仅仅会影响程序的风格和性能。

五、消除过期的对象引用

考虑下面栈实现的例子,你能否发现内存泄露的位置:

public class Stack {
private Object[] elements;
private int size = 0; public Stack(int initialCapacity) {
this.elements = new Object[initialCapacity];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
} public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
} /**
* 确保空间能存储一个以上的元素,当数组需要增加的时候仅仅是简单的将容量加倍
*/
private void ensureCapacity() {
if (elements.length == size) {
Object[] oldElements = elements;
elements = new Object[2 * elements.length + 1];
System.arraycopy(oldElements, 0, elements, 0, size);
}
}
}

从栈中弹出来的对象将不会当做垃圾回收,即使使用栈的客户程序不再引用这些对象,它们将不会回收。这是因为,栈内部维护这对这些对象的过期引用(过期引用,即永远也不会再被解除的引用),本例中凡是elements数组活动区域之外的引用都是过期的,elements的活动区域是指下标小于size的那一部分。

要想修复该问题很简单,一旦对象引用已经过期,只需要清空这些引用即可。pop方法的修订版如下:

public Object pop() {
if (size==0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // 删除过期引用
return result;
}

“清空度对象引用”这样的操作应该是一个例外,而不是一种规范行为。消除过期引用最好的办法是重用一个本来已经包含对象引用的变量,或者让这个 变量结束期声明周期。何时清除一个引用,Stack哪方面的特性使得它遭受到了内存泄露的影响?

根源在于Stack自己管理内存,存储池包含了elements数组(对象引用单元,而不是引用本身)的元素。数组活动区域中的元素是已分配的,而数组其余部分的元素是自由的。但垃圾回收器不知道,需要程序员手动清空。

六、避免使用终结函数

显示的终止方法通常与try-finally结构结合起来使用,以确保及时终止。

// try-finally 块保证终结方法的执行
Foo foo = new Foo(...);
try {
// 对fool执行一些必须操作
...
} finally {
foo.terminate(); // 显示终结方法
}

另一种方法是“终结函数链(finalizeer chaining)”不会自动执行,如果一个类(不是Object类)有一个终结函数,并且只有一个子类改写了终结函数,那么子类的终结函数必须手工调用父类的终结函数。

 // 手工终结链
protected void finalize() throws Throwable {
try {
// 终结子类的状态
...
} finally {
super.finalize();
}
}

即使子类的终结过程中跑出一个异常,超类的终结函数也会被执行,反之亦然。
但是如果子类改写了超累的终结函数,但是忘记调用超累的终结函数(或者有意不调用),会使得超类的终结函数永远得不到执行。为了解决这一问题,我们使用匿名类的单个实例(即终结函数守卫者)来终结其外围实例。

// 终结函数守卫者
public class Foo {
// 此对象的唯一目的是终结微微的Fool对象
private final Object finalizerGuardian = new Object() {
protected void finalize() throws Throwable {
// 终结外围的 Foo 对象
...
}
}; // 匿名类
... // 余下省略
}

公有类Fool并没有终结函数(除了它从Object中继承了一个无关紧要的finalize之外),所以子类的终结函数是否调用super.finalize并不重要,对于每一个带有终结函数的公有非final类,都应该考虑使用这项技术。

Java高效编程之一【创建和销毁对象】的更多相关文章

  1. Effective Java(1)-创建和销毁对象

    Effective Java(1)-创建和销毁对象

  2. effective java 第2章-创建和销毁对象 读书笔记

    背景 去年就把这本javaer必读书--effective java中文版第二版 读完了,第一遍感觉比较肤浅,今年打算开始第二遍,顺便做一下笔记,后续会持续更新. 1.考虑用静态工厂方法替代构造器 优 ...

  3. 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器

    类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...

  4. Effective Java——(一)创建和销毁对象

    第一条 考虑用静态工厂方法代替构造器 什么叫静态工厂方法,就是通过在类中通过静态方法对对象初始化. 比如说 public class StaticFactory { private String na ...

  5. Effective Java 读书笔记之一 创建和销毁对象

    一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...

  6. Effective Java 学习笔记之创建和销毁对象

    一.考虑用静态工厂方法代替构造器 1.此处的静态工厂方法是指返回指为类的对象的静态方法,而不是设计模式中的静态工厂方法. 2.静态工厂方法的优势有: a.使用不同的方法名称可显著地表明两个静态工厂方法 ...

  7. 【Effective Java】第二章-创建和销毁对象——1.考虑用静态工厂方法代替构造器

    静态工厂方法的优点: 可以赋予一个具有明确含义的名称 可以复用唯一实例,不必每次新建 可以返回原实例类型的子类对象 可以在返回泛型实例时更加简洁 缺点: 类如果不含有共有的或者受保护的构造器,就不能被 ...

  8. Effective Java(一)—— 创建和销毁对象

    在客户端(调用端)获取自身实例的方法: 公有的构造器: 类的静态工厂方法: 1. 使用静态工厂方法代替构造器 Boolean 是对基本类型 boolean 的包装类: public final cla ...

  9. 《Effective Java》—— 创建与销毁对象

    本篇主要总结的是<Effecticve Java>中关于创建和销毁对象的内容. 比如: 何时以及如何创建对象 何时以及如何避免创建对象 如何确保及时销毁 如何管理对象销毁前的清理动作 考虑 ...

  10. effective java读书小记(一)创建和销毁对象

    序言 <effective java>可谓是java学习者心中的一本绝对不能不拜读的好书,她对于目标读者(有一点编程基础和开发经验)的人来说,由浅入深,言简意赅.每一章节都分为若干的条目, ...

随机推荐

  1. ArcGIS Engine开发之旅04---ARCGIS接口详细说明

    原文:ArcGIS Engine开发之旅04---ARCGIS接口详细说明 ArcGIS接口详细说明... 1 1.      IField接口(esriGeoDatabase)... 2 2.    ...

  2. SQL Server中的Image数据类型的操作

    原文:SQL Server中的Image数据类型的操作 准备工作,在库Im_Test中建立一张表Im_Info,此表中有两个字段,分别为Pr_Id (INT),Pr_Info (IMAGE),用来存储 ...

  3. LeetCode -- Triangle 路径求最小和( 动态规划问题)

    Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent n ...

  4. notepad++的环境变量

    notepad++的环境变量:当前目录:$(CURRENT_DIRECTORY) cmd /k cd /d $(CURRENT_DIRECTORY)文件名:$(NAME_PART)路径名:$(CURR ...

  5. Linux是怎么启动的

    按下电源按钮的直到欢迎页出来之后,linux总共做的事可以分为五步来完成. 1. BIOS加电自检: 加电自检,检测硬件设备.然后按照cmos上面的顺序来搜索处在活动状态下的可以引导的设备.可以是光驱 ...

  6. 【Netty学习】 ChannelInitializer 学习

    ChannelInitializer在Netty中是一个很重要的东西.也是4.x版本中用户接触比较多的一个类 它本身是继承ChannelInboundHandlerAdapter的.实现Channel ...

  7. iOS多线程知识总结--GCD

    iOS多线程知识总结--GCD 1. iOS中苹果提供4钟方案来帮助我们实现多线程: (1) 纯C语言的pthread,偏底层,需要程序员手动管理线程的生命周期,基本不用. (2) OC语言的NSTr ...

  8. 10月12号 晚八点 Speed-BI 云平台-基于Excel数据源的管理驾驶舱构建全过程,腾讯课堂开课啦

    认真地做了一大摞一大摞的报表,老板没时间看?努力把能反馈的内容都融汇进图表里,老板嫌复杂?做了几个简单的报表,老板一眼就觉得信息不全面?每个报表都用了各种各样的图表,老板却毫无兴趣?明明很努力了,为什 ...

  9. [MVCSharp]开始使用MVC#

    Getting started with MVC# framework The source code of this example can be found under "Example ...

  10. 【杂记】SQL篇

    21.事务 22.左联右联 23.大小写转换 24.MySql字符串拼接 25.查询数据库表总数 26.Oracle虚拟表 27.判断是否为空 28.SQL取diff 29.存储过程proc 30.创 ...